2010-03-12 7 views
6

Tôi nhận được một java outOfMemoryError khi tôi gọi phương thức này - tôi đang sử dụng nó trong một vòng lặp để phân tích cú pháp nhiều tệp lớn theo thứ tự. tôi đoán là result.toString() không nhận được rác được thu thập đúng cách trong vòng lặp. nếu có, tôi nên sửa nó như thế nào?java outOfMemoryError với trình tạo chuỗi

private String matchHelper(String buffer, String regex, String method){ 
    Pattern abbrev_p = Pattern.compile(regex);//norms U.S.A., B.S., PH.D, PH.D. 
    Matcher abbrev_matcher = abbrev_p.matcher(buffer); 
    StringBuffer result = new StringBuffer(); 
    while (abbrev_matcher.find()){ 
      abbrev_matcher.appendReplacement(result, abbrevHelper(abbrev_matcher)); 
    } 
    abbrev_matcher.appendTail(result); 
    String tempResult = result.toString(); //ERROR OCCURS HERE 
    return tempResult; 

} 
+2

Làm thế nào lớn là "tệp lớn"? Có thể bạn chỉ không phân bổ đủ bộ nhớ cho JVM. – Ash

+0

Hiển thị văn bản lỗi để điều tra thêm. – Artic

+0

Làm thế nào về Chuỗi thuần túy của Độ dài OString: 2769348? Hầu hết các chuỗi là nexString của các bức ảnh được chụp –

Trả lời

6

Được viết theo cách này, bạn sẽ cần khoảng byte bộ nhớ cho mỗi ký tự trong tệp.

Mỗi ký tự là hai byte. Bạn có đầu vào thô, đầu ra được thay thế (trong bộ đệm), và bạn đang yêu cầu một bản sao thứ ba khi bạn hết bộ nhớ.

Nếu tệp được mã hóa dưới dạng ASCII hoặc ISO-8859-1 (mã hóa ký tự một byte), điều đó có nghĩa là tệp sẽ lớn hơn gấp 6 lần bộ nhớ so với trên đĩa.

Bạn có thể cấp thêm bộ nhớ cho quy trình, nhưng giải pháp tốt hơn có thể là xử lý đầu vào "streamwise" — đọc, quét và ghi dữ liệu mà không cần tải tất cả vào bộ nhớ cùng một lúc.

+1

Thumbs up. Nếu quá trình xử lý của bạn dựa trên công việc từng dòng, bạn có thể sử dụng nó: 'BufferedReader rd = new BufferedReader (FileReader mới ("/path/to/your/file "));' và gọi 'readLine () 'trong một vòng lặp' while', sau đó thực hiện thay thế và làm bất cứ điều gì là cần thiết với dòng đã thay đổi. – dimitarvp

0

Bạn có thể thử trả lại một StringBuffer và đặt nó vào null sau khi sử dụng.

2

Nếu tệp của bạn được xử lý đều rất lớn, giả sử hơn vài trăm MB thì bạn thực sự nên xử lý luồng thay vì "tải tất cả vào bộ nhớ" này, giống như @erickson đề xuất.

Nếu không, có một vài điều bạn có thể thử, tất cả để giảm sử dụng bộ nhớ càng nhiều càng tốt:

  1. Cố gắng đúng cách phóng to kích thước heap của bạn nếu chưa (khi áp dụng).
  2. Tặng StringBuffer kích thước ban đầu giống như chiều dài của Stringbuffer nhất định. Điều này sẽ làm giảm việc sử dụng bộ nhớ không cần thiết trong khi mở rộng StringBuffer trong quá trình này. Tôi cho rằng nó chỉ thay thế một số từ nhất định của chuỗi gốc và phải dài hơn hoặc ít hơn.
  3. Nếu có thể, có thể bạn có thể trả lại đối tượng StringBuffer được tạo. Gọi số toString() chỉ sau khi bạn thoát khỏi đối tượng String gốc.
+0

mở rộng vùng kích thước heap. –

1

Tôi đồng ý với các phản hồi khác ... nhưng ... đơn giản vì ngoại lệ xảy ra không có nhất thiết phải có nghĩa là đó là vấn đề. Bạn rất có thể là leaking memory ở nơi khác và điều đó chỉ xảy ra là nơi mà nó được tiết lộ. Bạn nên chạy profiler để kiểm tra mức sử dụng bộ nhớ và xác minh chính xác đối tượng nào không được thu thập.

1

Tôi xem xét sự cố với StringBuilder.append(). Khi Matcher nối chuỗi ký tự vào Builder.

Như được giải thích trong bài viết về OutOfMemoryError with StringBuilder/StringBuffer, đó là vấn đề đã biết gắn thêm() sẽ tăng gấp đôi dung lượng nếu bộ đệm trong chars nếu dung lượng không đủ. Chuyển đến các luồng theo đề xuất của Erickson.