我不明白当 JVM 使用的总内存 (Runtime.totalMemory()) 大约是可分配内存 (Runtime.maxMemory()) 的一半时,怎么可能会出现此异常。有什么想法吗?
Total Memory : 1708MB as returned by Runtime.getRuntime().totalMemory()
Max. Memory : 3545MB as returned by Runtime.getRuntime().maxMemory()
JRE : Java HotSpot(TM) 64-Bit Server VM : 1.6.0_29 (Linux)
最佳答案
正如 pcalcao 所提到的,JVM 告诉您它在垃圾收集上花费了太多时间,并且没有做足够的实际工作,所以它只是要退出。
这是一种安全阀,可以避免您实际上并没有用完内存,但已经足够接近以至于您确实没有取得任何进展的情况。我不会重复这一点 - this answer有很多细节,但我会提到一些可能适用于您的情况的事情:
如果您SoftReference
,这更有可能发生s 缓存东西——随着堆增长到最大大小,这些引用被清除并可能重复重新生成(取决于你的关键循环是否触及)它们,导致一些不良行为,GC 不断发生但总是恢复足够的内存以继续前进因为它能够清除一些软引用——即使是 JDK 也会遇到这种情况,因为他们在 Locale
中使用了这种缓存。类。
如果你真的想使用 -XX:-UseGCOverheadLimit,你可以禁用这个行为。不过,它所指示的问题是真实存在的 - 您花费的运行时间不到 2% 用于实际工作。
你在哪里打印出这些内存值?根据您的程序的结构,它可能会产生大量垃圾并在某些内部循环中使用大部分堆,但在您放置诊断输出的地方,垃圾已被回收。 -verbose:gc 可以让您更好地了解实际的 GC 行为。
关于Java : "GC Overhead limit exceeded" despite plenty of memory to allocate available,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14077813/