Java在产生OutOfMemory错误之前等了20个小时?

时间:2014-09-27 19:52:36

标签: java memory-management out-of-memory

我有一个复杂的Java与Scala代码混合在一起读入输入文件并在逐行处理行时创建大量数据结构,包括从输入开始长度为10的所有子串的哈希表。 / p>

我最初使用-Xmx4g开关运行代码,代码在返回OOM错误之前花了 20小时,并且没有完全通过文件。

然后我使用-Xmx32g运行代码,代码在 8分钟中处理文件中的所有行,然后继续处理已读取的数据结构。 8分钟后,Java使用的驻留内存约为21GB。

我的问题是:为什么Java在8分钟内没有返回OOM错误?这20小时做了什么?

3 个答案:

答案 0 :(得分:3)

根据您的描述,我愿意打赌您遇到的OutOfMemoryError标记为“java.lang.OutOfMemoryError:超出GC开销限制”。独立如果我的赌注是正确的,情况的描述与下面发生的事情完全匹配:

  • 您将一些数据加载到内存中
  • GC开始并清理了一些。在每次GC完成工作期间,它都会暂停应用程序线程。
  • 你加载了更多的东西,触发了更多的GC,但是在每个GC之后,恢复的内存越来越少。
  • 垃圾收集的频率增加,直至实际进展很少
  • JVM有一个内置的安全网来捕捉这些情况 - 每当你在GC中花费超过98%的时间并且只能恢复2%或更少的堆时,“java.lang.OutOfMemoryError:GC开销超出限制“抛出错误。

要检测此类情况,您可以打开GC日志(例如-verbose:gc或-XX:+ PrintGCDetails)并密切关注暂停时间。

答案 1 :(得分:1)

垃圾收集是非确定性和复杂的。这与JIT编译等其他内容相结合,使得精确的内存使用模式难以预测和复制。

你提到它包括Scala?这让事情变得更有趣。 "很好"功能构造可能产生比它看起来更多的垃圾。即使像Option-s中包装对象这样的小东西也需要额外的内存来清理。

答案 2 :(得分:0)

Java有一个垃圾收集器线程。如果它发现它可以收集足够的垃圾以释放空间,那么它就会这样做。

因此,我建议使用可视化虚拟机并监控下次垃圾收集所花费的时间。