JVM垃圾收集器似乎失败了

时间:2015-04-21 19:30:30

标签: java garbage-collection out-of-memory

我们有一个java应用程序,它可以读取一大块数据,但只能在短时间内保存这些数据。数据存储在“简单”集合中(HashMapHashSet)。处理数据时会清除这些集合(因此我调用coll.clear()而不是coll=null)。循环(读取 - 处理 - 清除)继续,直到“处理所有数据块”。经过一段时间后,会出现“新块”,整个事情又开始了。

此过程在服务器上运行了几个星期没有任何问题。 但是,今天,在计划重新启动之后,它一次又一次地使用OutOfMemoryError: Java heap space崩溃(并由监控过程自动重启)。

我使用远程调试器和 jvisualvm 工具连接到该进程,以尝试查找是否(以及在哪里)我可能有内存泄漏。在调用clear()之后,处理线程暂停(由调试器),我使用jvisualvm工具强制gc。正如我所料,它几乎清除了整个堆(仅使用了4MB)。接下来的周期:相同的行为,在clear之后几乎没有使用堆等等......最后,该过程已经不在内存中了!

对我来说,垃圾收集器看起来无法正常工作......

  • 我该如何验证是否属实?
  • 如果是的话,怎么会这样?
  • 我应该在System.gc()方法之后调用clear()吗?

    但据我所知(并阅读here),这只是对VM的“建议”;当堆几乎满时,GC将始终收集所有可能的垃圾;应该简单地避免这样的呼叫: - )......

(我们在Solaris上以服务器模式运行Java 1.6.0_51-b11,没有特殊的GC选项)

分析堆转储后

编辑

我们的代码具有以下结构:

final DataCollector collector = ...
while (!collector.isDone()) {
    final List<Data> dataList = collector.collectNext();
    for (final Data data : dataList) {
        // process data...
    }
}

执行OOMError方法时发生collector.collectNext()

看起来堆仍然包含dataList循环的上一个迭代的while变量(和所有数据对象)!

while循环的局部变量不会被垃圾收集,这是正常的行为吗?如果这是真的,我们必须给这个过程几乎两倍于严格需要的内存......

作为hack / check,我在for循环之后添加了一行dataList = null,但是这并没有改变行为(仍然是OOM,堆转储仍然显示相同的'双重赋值')

(我想我们很幸运,这个过程没有提前崩溃。)

2 个答案:

答案 0 :(得分:0)

我遇到了垃圾收集器在一定时间后出现问题并且出现虚假OOME的问题。当你有一个复杂的具有大量圆圈的物体链时,往往会发生这种情况。解决方案是使用-XX:-UseGCOverheadLimit标志告诉垃圾收集器不要放弃。

答案 1 :(得分:0)

我遇到了同样的问题,我所做的是:

通过转到Project > Clean > Clean all projects (tick this option)

清洁项目

如果问题仍然存在,则需要重构代码,并消除内存泄漏。