我有一个非常复杂的遗留代码
有时执行它会生成java.lang.OutOfMemoryError : GC overhead limit exceeded
确定此来源的正确方法是什么?
代码非常复杂(多个哈希映射,字符串操作等)
答案 0 :(得分:1)
java.lang.OutOfMemoryError : GC overhead limit exceeded
是由于GC相对于在应用程序代码中花费的CPU时间而花费了太多的CPU时间。
换句话说,GC估计它没有足够的进展来保持应用程序以合理的吞吐量运行。
有三种可能的原因:
要确定A),您需要配置文件分配率。
B)可以通过提高堆限制来解决。
C)与B)的不同之处在于它在增加堆大小后仍然会抛出。在这种情况下,您只需启用-XX:+HeapDumpOnOutOfMemoryError
并分析泄漏对象的转储。
在少数情况下,启发式错误可能会被误导。在这些情况下,可以通过调整-XX:GCTimeRatio=
来放宽限制,以允许GC消耗更多CPU时间,或者只需使用-XX:-UseGCOverheadLimit
完全禁用它。但在大多数情况下,这只会延迟不可避免的内存不足 OOM。
答案 1 :(得分:0)
如果Java没有对可以花费多少时间进行垃圾收集施加限制,那么该程序需要的内存量可能会低于可用量。从来没有"失败",但可能需要数千倍来执行,而不是更多的内存。相反,一个需要大量内存的程序最终会因内存不足而失败,但可能会花费很长时间才能在发生之前完成任何事情。 Java的实现者添加了一些GC时间健全性检查的理念,即一个程序通常需要一秒钟才会执行失败并且在几秒钟之后出现内存不足错误比让程序突然停留一小时更好然后抛出一个内存不足的错误,并不比让它突然消失一小时并且可能成功更糟糕。
除非程序故意强制进行垃圾收集,否则每千字节临时分配的成本将与活动对象的数量除以收集后剩余的可用空间量成比例。随着内存利用率接近一定水平,这个数量将从非常小到真正巨大。因此,如果内存分配失败,那么它们会非常慢,这将有效地减少程序可用的内存量,但不会太多。