在Java中处理字符串时发生OutOfMemoryException

在Java中处理字符串时发生OutOfMemoryException,java,memory-management,csv,Java,Memory Management,Csv,我有这样的情况:我从CSV文件中读取行并将它们放到列表中。完成后,根据特殊逻辑解析行,并将它们的部分作为键放入几个HashMap中。然后清除列表记录。实际上我试过几种方法: records.clear(); records = null; records = new ArrayList<String>(); 但似乎内存并没有被释放,而是通过使用探查器和简单的打印控制台来检查它。由于这种读取文件的迭代和进一步的解析被重复了好几次,在某一时刻我得到了一个OutOfMemoryError

我有这样的情况:我从CSV文件中读取行并将它们放到列表中。完成后,根据特殊逻辑解析行,并将它们的部分作为键放入几个HashMap中。然后清除列表记录。实际上我试过几种方法:

records.clear();
records = null;
records = new ArrayList<String>();
但似乎内存并没有被释放,而是通过使用探查器和简单的打印控制台来检查它。由于这种读取文件的迭代和进一步的解析被重复了好几次,在某一时刻我得到了一个OutOfMemoryError

有人能提出解决办法吗?用Java能解决这个问题吗?或者字符串池对于垃圾收集器来说是不可忽略的?也许C++等其他语言更适合?< /P>
谢谢。

我们需要更多的代码来查看您是否有内存泄漏

您是否考虑过在列表中存储更少的行,而不是读取列表中的整个文件? 此外,您可以尝试一起取消中间结构

阅读100行并将其添加到列表中 遍历、解析并添加到hashmaps。 清除列表 您可以增加堆大小,但如果没有发现泄漏,如果遇到非常大的文件大小,则可能导致另一个异常。很好,德斯特罗伊指出了这一点

增加堆的说明如下:


示例:java-Xmx6g myprogram

我们需要更多的代码来查看是否存在内存泄漏

您是否考虑过在列表中存储更少的行,而不是读取列表中的整个文件? 此外,您可以尝试一起取消中间结构

阅读100行并将其添加到列表中 遍历、解析并添加到hashmaps。 清除列表 您可以增加堆大小,但如果没有发现泄漏,如果遇到非常大的文件大小,则可能导致另一个异常。很好,德斯特罗伊指出了这一点

增加堆的说明如下:


示例:java中的java-XMX6GmyProgram运行良好。如果您得到OutOfMemoryError,则可能是内存泄漏,即在集合中存储了太多内存,或者没有为应用程序提供足够的堆

我相信,在您的情况下,您不会到达清除集合的代码。解析过程中可能会失败。在本例中,首先尝试使用命令行选项-Xmx(例如-xmx1024m1gb)向java进程添加更多内存

我相信您将能够找到帮助您成功完成解析的选项

然后,若您正在使用一个实用程序,该实用程序将解析文件一次并终止,那个么就完成了。但是,如果您的应用程序应该运行并解析越来越多的文件,请检查在处理每个文件后内存使用是否没有增加。如果它正在增长,检查它是由设计引起的还是由bug引起的


如果是设计,考虑重新设计。顺便说一句,你真的必须把所有的行读入内存,然后处理它们吗?你在做什么样的处理?是否有可能逐行处理文件并显著降低内存使用率?

java中的GC工作得很好。如果您得到OutOfMemoryError,则可能是内存泄漏,即在集合中存储了太多内存,或者没有为应用程序提供足够的堆

我相信,在您的情况下,您不会到达清除集合的代码。解析过程中可能会失败。在本例中,首先尝试使用命令行选项-Xmx(例如-xmx1024m1gb)向java进程添加更多内存

我相信您将能够找到帮助您成功完成解析的选项

然后,若您正在使用一个实用程序,该实用程序将解析文件一次并终止,那个么就完成了。但是,如果您的应用程序应该运行并解析越来越多的文件,请检查在处理每个文件后内存使用是否没有增加。如果它正在增长,检查它是由设计引起的还是由bug引起的

如果是设计,考虑重新设计。顺便说一句,你真的必须把所有的行读入内存,然后处理它们吗?你在做什么样的处理?您是否有可能逐行处理文件并显著降低内存使用率?

您说过:

完成后,根据特殊逻辑解析行,并将它们的部分作为键放入几个HashMap中

如果您是通过类似String.substring的方式获取这些部分,那么该子字符串不是新的副本,它实际上是指向原始字符串,并且知道组成该子字符串的开始和索引

因此,只要这些子字符串存在,就不会对原始字符串进行垃圾收集。如果这些子字符串被传递到系统的其他部分,则清除集合将没有帮助

您需要确保创建了一个全新的字符串,例如:

new String( myString.substring( 1, 5 ) );
这里有一个链接,谷歌搜索的字符串子字符串指向origi 纳尔。

尽管JDK 1.7的后续版本显然已经根据以下内容修复了此问题: 你说过:

完成后,根据特殊逻辑解析行,并将它们的部分作为键放入几个HashMap中

如果您是通过类似String.substring的方式获取这些部分,那么该子字符串不是新的副本,它实际上是指向原始字符串,并且知道组成该子字符串的开始和索引

因此,只要这些子字符串存在,就不会对原始字符串进行垃圾收集。如果这些子字符串被传递到系统的其他部分,则清除集合将没有帮助

您需要确保创建了一个全新的字符串,例如:

new String( myString.substring( 1, 5 ) );
这里有一个链接,它看起来像谷歌搜索的原始字符串的子字符串点。

尽管JDK 1.7的后续版本显然已经根据以下内容修复了此问题:

如果用记录列表中的行的子字符串填充这些hashmap,那么实际上是为每个子字符串完全存储这些行

看看:

在这种情况下,答案是使用类似以下内容:

String key = new String(record.substring(6,12));


若用记录列表中的行的子字符串填充这些hashmap,那个么实际上是为每个子字符串完全存储这些行

看看:

在这种情况下,答案是使用类似以下内容:

String key = new String(record.substring(6,12));


垃圾收集器仅在您丢失对对象的所有引用时工作。您说一些信息存储在HashMap中,所以垃圾收集器不会删除它们

垃圾收集器只有在您丢失对对象的所有引用时才能工作。您说一些信息存储在HashMap中,所以垃圾收集器不会删除它们

可能是因为你有足够的内存,但内存是零碎的。如何构建ArrayList和HashMap至关重要。例如,您是否正在使用StringBuilder

除非显示错误之前的全部代码,否则很难远程调试内存问题

此外,如果我们了解java版本、环境等,这也会有所帮助

另外,不要忘记,如果您有许多大小不同的对象,那么内存会更容易碎片化。如果内存不足以容纳这些对象,可能会出现内存错误


最后,您可以启动自己的垃圾收集,JVM很可能会更清楚:您可能有足够的内存,但内存是碎片化的。如何构建ArrayList和HashMap至关重要。例如,您是否正在使用StringBuilder

除非显示错误之前的全部代码,否则很难远程调试内存问题

此外,如果我们了解java版本、环境等,这也会有所帮助

另外,不要忘记,如果您有许多大小不同的对象,那么内存会更容易碎片化。如果内存不足以容纳这些对象,可能会出现内存错误


最后,您可以启动自己的垃圾收集—最有可能JVM会知道的是:-。

我们需要更多的代码来告诉您发生了什么……您是否清除了哈希映射?您有数百万行吗?您使用的是哪种Java版本?这会有很大的不同。文件有多大?您有多少内存?请确保所有对字符串的引用都消失了。如果仍然可以从任何地方找到它们,它们将不会被收集。如果你有成吨的行,并且你把这些字符串存储在一堆不同的hashmap中,你可能只是内存不足,简单明了。尝试使用探查器确定哪些对象包含对所有这些字符串或其他对象的引用!我们需要更多的代码来告诉您发生了什么……您是否清除了hashmaps?您是否有数百万行?您使用的是哪一版本的Java?这会有很大的不同。文件有多大?您有多少内存?请确保所有对字符串的引用都消失了。如果仍然可以从任何地方找到它们,它们将不会被收集。如果你有成吨的行,并且你把这些字符串存储在一堆不同的hashmap中,你可能只是内存不足,简单明了。尝试使用探查器确定哪些对象包含对所有这些字符串或其他对象的引用!增加堆大小而不是查找问题看起来像是一种不好的反射。这是正确的!你说的很好。我们需要从OP中获得更多的代码,以查看是否确实存在内存泄漏。但是,可能通过增加堆来解决用户的问题。此外,一次读取较少的行,将问题分解为较小的行也会起作用。增加堆大小而不是查找问题看起来像是一种不好的反射。这是正确的!你说的很好。我们需要从OP中获得更多的代码,以查看是否确实存在内存泄漏。可能是 然而,这种情况下,用户的问题将通过增加堆来解决。此外,也许一次读更少的行,将问题分解成更小的行也会起作用。