【问题标题】:Java : "GC Overhead limit exceeded" despite plenty of memory to allocate availableJava:“超出了 GC 开销限制”,尽管有足够的内存可供分配
【发布时间】:2012-12-29 01:13:22
【问题描述】:

当 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)

【问题讨论】:

  • 对不起,在之前的回答中我误导了你,我误读了一些仅与 RMI 相关的信息。

标签: java garbage-collection


【解决方案1】:

正如 pcalcao 所提到的,JVM 告诉您它在垃圾收集上花费了太多时间,并且没有做足够的实际工作,所以它只会退出。

这是一种安全阀,可以避免您实际上并没有耗尽内存,但已经足够接近以至于您确实没有取得任何进展的情况。我不会详细说明这一点 - this answer 有更多细节,但我会提到一些可能适用于您的案例的事情:

如果您 SoftReferences 缓存内容,则更有可能发生这种情况 - 随着堆向最大大小增长,这些引用将被清除并可能反复重新生成(取决于您的键循环是否触及)它们,从而导致一些GC 不断发生但总是恢复足够的内存以继续运行的不良行为,因为它能够清除一些软引用 - 甚至 JDK 也会受到这种影响,因为它们在 Locale 类中使用这种缓存。

如果你真的想使用 -XX:-UseGCOverheadLimit,你可以禁用这个行为。尽管如此,它所表明的问题是真实存在的——您花费不到 2% 的运行时间来做实际工作。

你在哪里打印出这些内存值?根据您的程序的结构,它可能会生成大量垃圾并在某个内部循环中使用大部分堆,但是在您放置诊断输出的地方,垃圾已被回收。 -verbose:gc 可以让您更好地了解实际的 GC 行为。

【讨论】:

  • 无软引用;在这种情况下没有缓存;一个处理分配线程......我真的需要那个 RAM:没有什么可以释放的。
  • 在编写良好的应用程序中出现此错误是不寻常的,因为您必须生成大量对象而几乎没有其他处理才能触发此错误,或者可能已经奇怪大小的几代人。 -verbose:gc 将成为你的朋友,也许与 jmap 或 jvisualvm 结合使用。
  • 更有可能我们得到了错误的日志信息;感谢您的意见,我已接受回复。您可能想知道 Max.内存可能大于操作系统中的可用内存(JVM 不检查)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-03
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
相关资源
最近更新 更多