8

当我调用这个方法时,我得到了一个 java outOfMemoryError - 我在循环中使用它来依次解析许多大文件。我的猜测是result.toString()在循环期间没有正确收集垃圾。如果是这样,我应该如何解决?

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;

}
4

6 回答 6

8

以这种方式编写,文件中的每个字符大约需要6个字节的内存。

每个字符是两个字节。您有原始输入、替代输出(在缓冲​​区中),并且当您用完内存时要求第三个副本。

如果文件以 ASCII 或 ISO-8859-1(单字节字符编码)之类的方式编码,则意味着它在内存中的大小将是磁盘上的六倍。

您可以为进程分配更多内存,但更好的解决方案可能是“流式”处理输入——读取、扫描和写入数据,而无需一次将其全部加载到内存中。

于 2010-03-12T07:20:13.763 回答
6

如果您要处理的文件都非常大,比如说超过几百 MB,那么您真的应该使用流处理而不是像 @erickson 建议的那样“将所有文件加载到内存中”的方式。

否则,您可以尝试一些方法,以尽可能减少内存使用量:

  1. 如果还没有(如果适用),请尝试适当地扩大您的堆大小。
  2. 给出StringBuffer与给定的长度相同的初始大小String buffer。这应该减少不必要的内存使用,同时扩展StringBuffer进程。我假设它只是替换原始字符串的某些单词,并且长度应该或多或少相同。
  3. 如果可能的话,也许您可​​以返回生成的StringBuffer对象。toString()只有在您摆脱原始String对象后才调用它。
于 2010-03-12T07:26:56.773 回答
2

我认为问题与StringBuilder.append(). 当 Matcher 将字符序列附加到 Builder 时。

正如在关于OutOfMemoryError with StringBuilder/StringBuffer的文章中所解释的那样,如果容量不足,append() 将使内部缓冲区的容量加倍是一个已知问题chars。按照 Erickson 的建议选择流。

于 2010-09-17T07:56:54.060 回答
1

我同意其他回应......但是......仅仅因为那里发生异常并不一定意味着它是问题所在。您很可能正在其他地方泄漏内存,而这恰好是它被揭示的地方。您应该运行分析器来检查内存使用情况并准确验证未收集哪些对象。

于 2010-03-12T07:29:34.980 回答
1

是的!不要在内存中缓冲,否则如果 I/O 超过 2MB,你会特别用完它。

修复和附加文本的推荐链接:http: //java.ittoolbox.com/documents/appending-data-to-a-file-18786

于 2010-10-01T15:51:53.833 回答
0

您可以尝试在使用后返回 aStringBuffer并将其设置为null

于 2010-03-12T07:09:52.123 回答