带有stringbuilder的java outOfMemoryError
当我调用这个方法时,我得到一个java outOfMemoryError – 我在一个循环中使用它来按顺序解析许多大文件。 我的猜测是result.toString()
在循环期间没有正确收集垃圾。 如果是的话,我该如何解决?
private String matchHelper(String buffer, String regex, String method){ Pattern abbrev_p = Pattern.compile(regex);//norms USA, BS, 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; }
以这种方式编写,对于文件中的每个字符,您将需要大约6个字节的内存。
每个字符都是两个字节。 你有原始输入,替换输出(在缓冲区中),并且当你的内存不足时你要求第三个副本。
如果文件以ASCII或ISO-8859-1(单字节字符编码)的forms编码,则意味着它的内存大6倍于磁盘。
您可以为进程分配更多内存,但更好的解决方案可能是处理输入“streamwise” – 读取,扫描和写入数据,而不是立即将其全部加载到内存中。
如果要处理的文件都非常大,比如说超过几百MB,那么你真的应该使用流处理而不是“加载所有内存”方式,就像@erickson建议的那样。
否则,您可以尝试一些方法,尽可能减少内存使用量:
- 如果还没有(适用时),请尝试正确扩大堆大小。
- 给
StringBuffer
一个初始大小,与给定String
buffer
的长度相同。 这应该在进程中扩展StringBuffer
时减少不必要的内存使用量。 我假设它只是替换原始字符串中的某些单词,并且长度应该大致相同。 - 如果可能,也许您可以返回生成的
StringBuffer
对象。 只有在删除原始String
对象后才调用其toString()
。
我同意其他回复……但是……仅仅因为发生exception并不一定意味着它就是问题。 你很可能在其他地方泄露记忆 ,而恰好是它所揭示的地方。 您应该运行一个分析器来检查内存使用情况并确切地validation哪些对象没有被收集。
我认为StringBuilder.append()
问题。 当Matcher将字符序列附加到Builder时。
正如在关于带有StringBuilder / StringBuffer的OutOfMemoryError的文章中所解释的那样,如果内容缓冲器在容量不足时发生变化,则append()将使容量加倍。 按照埃里克森的建议去寻找溪流。
是! 不要在内存中缓冲,否则如果你的I / O超过2MB,你将特别用完它。
修复和附加文本的推荐链接: http : //java.ittoolbox.com/documents/appending-data-to-a-file-18786
您可以尝试返回StringBuffer
并在使用后将其设置为null
。