在达到堆空间的最大值之前OutOfMemoryError?

时间:2015-04-20 17:25:37

标签: java memory garbage-collection out-of-memory heap

我遇到了一个非常奇怪的问题,我想在SSCCE中重现,但我不能。

我使用-Xmx1024m在Java8(32位)中运行我的程序,此代码使用FileInputStream将一个非常大的文件(120MB)加载到一个字节数组中。

问题在于,在Java6中我没有遇到任何问题,在Java8中,一旦我尝试加载它就会出现OutOfMemoryError个异常。

我仍然有很多内存空闲,而且我已经对它进行了分析,我认为没有问题。

如果我试图在SSCCE中解决这个问题,那么它就可以了。

我知道Oracle已经摆脱了PermGen,但这可能会如何影响我的程序?

我还读到它可能与堆空间的碎片问题有关,但是我试图调试它,对它进行分析,并在分配内存之前从分析器运行GC循环,它仍然在发生(我假设GC循环会对堆空间进行碎片整理)

3 个答案:

答案 0 :(得分:4)

使用Java8时,有一些新的东西被移到堆中,它们之前是PermGen Space的一部分,例如字符串池,也检查它分配的旧代的大小

答案 1 :(得分:1)

我想我找到了原因。根据这个错误报告:

https://bugs.openjdk.java.net/browse/JDK-6478546

FileInputStream将空间直接保留在本机内存中。增加Max堆空间的大小实际上更糟糕,因为本机映射的空间实际上更少。

我的代码使用Java8 64位的原因正是因为我有更多来自Windows的虚拟空间,而不是限制在Windows中的~1.7Gb。

我仍然不太清楚,为什么相同的代码在Java6中有效。似乎相同的应用程序在Java8中使用的本机空间比在Java6中更多。也许Metaspace的新方案改变了一些东西。我不确定。

有趣的文章:

http://www.codingthearchitecture.com/2008/01/14/jvm_lies_the_outofmemory_myth.html

答案 2 :(得分:0)

有几件事。

  • 1 GB并不多,即使在Windows 32位上也可以使它达到1400 MB。
  • Java 8与Java 6的工作方式不同,它的优化假设内存比9年前发布的Java 6便宜。
  • 您可以在120 MB的内存映射中完全不使用堆。这可能是一种更有效的方法
  • 消耗的内存几乎肯定是你对数据的处理方式,而数据可能是文件大小的很多倍。我不认为你实际上只使用120 MB来处理这个文件。

我建议你使用eh 64位JVM在内存中分析内存充足的内存,如果你必须要了解内存消耗的位置。