代码之家  ›  专栏  ›  技术社区  ›  jilles de wit

“java.lang.outOfMemoryError:超出GC开销限制”中GC时间过长的持续时间

  •  10
  • jilles de wit  · 技术社区  · 14 年前

    偶尔,在每2天一次到每2周一次之间,我的应用程序会在代码中看似随机的位置崩溃,其中包括: java.lang.OutOfMemoryError: GC overhead limit exceeded . 如果我搜索这个错误,我会 this SO question 这让我 this piece of sun documentation 其中:

    如果时间过长,并行收集器将抛出一个内存错误。 用于垃圾收集:如果总时间的98%以上 在垃圾收集中花费,并且回收的堆少于2%,则 将引发OutOfMemoryError。此功能旨在防止 应用程序在 由于堆太小,进度很少或没有进展。如果需要,这个 可以通过将选项-xx:-usegcoverheadlimit添加到 命令行。

    这告诉我,显然我的应用程序将98%的总时间花在垃圾收集上,以仅恢复堆的2%。

    但是98%的时间?整个两周中98%的时间应用程序都在运行?最后一毫秒的98%?

    我正在尝试确定一种实际解决这个问题的最佳方法,而不仅仅是使用 -XX:-UseGCOverheadLimit 但我觉得有必要更好地理解我正在解决的问题。

    3 回复  |  直到 12 年前
        1
  •  6
  •   Bill the Lizard Alexis MP    12 年前

    我正在尝试确定一种实际解决这个问题的最佳方法,而不仅仅是使用 -XX:-UseGCOverheadLimit 但我觉得有必要更好地理解我正在解决的问题。

    嗯,你用的内存太多了——从声音上看,可能是因为内存泄漏太慢。

    您可以尝试使用 -Xmx 如果这不是内存泄漏,而是应用程序实际需要大量堆的迹象,并且当前的设置略低,这将有所帮助。如果是内存泄漏,这将推迟不可避免的事情。

    要调查它是否是内存泄漏,请指示VM使用 -XX:+HeapDumpOnOutOfMemoryError 切换,然后分析堆转储,以查看是否存在比应有的更多的某种对象。 http://blogs.oracle.com/alanb/entry/heap_dumps_are_back_with 是个不错的开始。


    编辑: 正如命运所愿,我在这个问题被问到的第二天,在一个批处理风格的应用程序中,碰巧遇到了这个问题。这不是由内存泄漏引起的,增加堆大小也没有帮助。我所做的实际上是 减少 堆大小(从1GB到256MB)可以使完整的GC更快(尽管更频繁)。嗯,但值得一试。

    编辑2: 不是所有的问题都由较小的堆解决…下一步是启用 G1 garbage collector 这似乎比CMS做得更好。

        2
  •  1
  •   MSalters    14 年前

    98%的内存将在恢复不到2%的内存的同一时间段内进行测量。

    很可能没有固定的期限。例如,如果OOM检查将在每1000000个对象实时检查之后进行。所需时间取决于机器。

    你很可能无法通过添加 -XX:-UseGCOverheadLimit . 最有可能的结果是,应用程序将缓慢爬行,使用更多的内存,然后达到GC根本无法恢复的程度。 任何 记忆不再。相反,修复内存泄漏,然后(如果仍然需要)增加堆大小。

        3
  •  1
  •   Stephen C    12 年前

    但是98%的时间?整个两周中98%的时间应用程序都在运行?最后一毫秒的98%?

    简单的答案是没有指定。然而,在实践中,启发式的“有效”,所以它不能是你所假定的两种极端解释中的任何一种。

    如果你 真正地 为了找出测量的时间间隔,您总是可以读取OpenJDK 6或7源代码。但我不会费心,因为这帮不了你解决问题。

    “最佳”方法是阅读一些关于调优的内容(从Oracle/Sun页面开始),然后小心地“旋转调优旋钮”。它不是很科学,而是问题空间(准确地说 预测 应用程序+GC性能)太难了,因为目前有可用的工具。