我有这样的情况:我从CSV文件中读取行并将它们放到List<String>
。完成后,根据特殊逻辑解析行,并将它们的部分作为键放入几个HashMap<String, Integer>
。然后清除列表记录。实际上我尝试了几种方法:
records.clear();
records = null;
records = new ArrayList<String>();
但似乎无论如何都没有释放内存(通过使用分析器和简单的打印到控制台来检查它)。由于这种迭代与文件读取和进一步解析重复几次,我得到一个OutOfMemoryError
。
有人可以在这里提出任何解决方案吗?是否有可能用Java来解决它?或者垃圾收集器的字符串池是不是可以忽略不计?也许像C ++这样的其他语言更合适?
谢谢。
答案 0 :(得分:3)
你说:
完成后,根据特殊逻辑解析行,并将它们的部分作为键放入几个HashMap中。
如果您通过String.substring之类的东西获取这些部分,那么该子字符串不是新副本,它实际上指向原始字符串,并且知道包含子字符串的begin和索引。
因此,只要存在任何这些子字符串,就不会对原始字符串进行垃圾回收。如果将这些子字符串传递给系统的其他部分,则清除您的集合将无济于事。
您需要确保创建了一个全新的字符串,例如:
new String( myString.substring( 1, 5 ) );
这是一个看起来不错的链接(Google搜索“String substring points at original”)。 http://javarevisited.blogspot.com/2011/10/how-substring-in-java-works.html
虽然显然后来JDK 1.7版本已根据此修复了此问题: how the subString() function of string class works
答案 1 :(得分:1)
我们需要更多代码才能看到你的某处是否有“内存泄漏”。
您是否考虑过在列表中存储较少的行而不是读取列表中的整个文件? 此外,您可以尝试一起取消中间结构。
您可以增加堆大小,但如果您没有找到泄漏,如果遇到非常大的文件大小,这可能会导致另一个异常。很好的解决方法指出了这一点。
增加堆的说明如下: Increase heap size in Java
示例:java -Xmx6g myprogram
答案 2 :(得分:1)
java中的GC效果很好。如果你得到OutOfMemoryError
,你可能有内存泄漏(即你在集合中存储太多)或者你的应用程序没有足够的堆。
我相信在您的情况下,您没有到达清除集合的代码。您可能在解析过程中失败了。在这种情况下,首先尝试使用命令行选项-Xmx
为您的Java进程添加更多内存,例如-Xmx1024M
(1GB)。
我相信您将能够找到有助于您的解析成功完成的选项。
然后,如果您正在使用解析文件一次并终止的实用程序,那么您就完成了。但是,如果您的应用程序应运行并解析越来越多的文件,请检查在处理每个文件后内存使用量是否没有增长。如果它正在增长,请检查它是否是设计或是由bug引起的。
如果是设计,请考虑重新设计。顺便说一句,你真的必须将所有行读入内存然后处理它们吗?你在做什么样的处理?您是否有可能逐行处理文件并大幅减少内存使用量?
答案 3 :(得分:1)
如果用records
列表中的行的子字符串填充这些哈希映射,实际上就是为每个子字符串完全存储这些行。
查看:Memory leak traps in the Java Standard API
在这种情况下的答案是使用类似的东西:
String key = new String(record.substring(6,12));
或
String key = record.substring(6,12).intern();
答案 4 :(得分:1)
可能是你有足够的内存,但内存是碎片。如何构建ArrayList和HashMap至关重要。例如。正在使用StringBuilder
?
除非显示出错误的整个代码,否则很难远程调试内存问题。
此外,如果我们知道java版本,环境等,它会有所帮助。
另外,不要忘记,如果你有很多不同大小的对象,内存变得更容易碎片化。如果内存几乎不足以包含这些对象,则可能会出现内存错误。
最后,您可以启动自己的垃圾收集( - 很可能JVM会更好地了解:-))。
答案 5 :(得分:0)
垃圾收集器仅在您放弃对Object的所有引用时才起作用。你说有些信息存储在HashMap中,所以垃圾收集器不会替换它们。