超出了GC开销限制,但内存仍然存在

时间:2016-10-12 09:53:01

标签: java garbage-collection

我有一个

java.lang.OutOfMemoryError: GC overhead limit exceeded

分裂一些字符串。有趣的是,内存都没用完,垃圾收集器也不会发疯:JVisualVM output

异常出现在11点10分,当时Eclipse在实际抛出异常之前冻结了程序。所以11点10分之后的所有事情都可能只是噪音。

我在长期运行的程序中反复遇到这个问题,但我不知道如何避免它。即使分配更多的内存也只会延迟,但不能阻止它。

1 个答案:

答案 0 :(得分:2)

你正在使用stop-the-world GC(可能是Parallel Scavenge)。这个例外是因为GC需要太多时间,这可能超过总执行时间的98%。在这种情况下,JVM会杀死进程,因为没有真正的工作。

解决方案可能是:

  1. 尝试其他类型的GC,例如Concurrent Mark Sweep,它不是世界各地的GC;
  2. 尝试更大的内存,因此GC并不常见;
  3. 使用-XX:-UseGCOverheadLimit忽略此GC时间限制,这可能会导致问题,因为JVM一直在使用GC而不是实际工作;
  4. 如上所述,使用-XX:+HeapDumpOnOutOfMemoryError转储内存跟踪并分析跟踪。
  5. 更多解释为什么堆不满但GC超限(所有这些都是猜测,需要更多的跟踪来确定原因): 这可以是

    1. 太小的年轻一代或大多数对象都存在于次要GC中,因此GC过于频繁和/或花费很长时间移动对象(这可能通过改变堆上的年轻代大小或通过某些JVM更改对象的使用率来调整旗);
    2. 从较小的GC中幸存下来的对象太小的旧生成大小无法适应老一代,这会导致频繁的主要GC(或完整堆GC)。