【问题标题】:Duration of Excessive GC Time in "java.lang.OutOfMemoryError: GC overhead limit exceeded"“java.lang.OutOfMemoryError:GC 开销限制超出”中的过度 GC 时间的持续时间
【发布时间】:2011-02-21 06:45:26
【问题描述】:

有时,在每 2 天一次到每 2 周一次之间,我的应用程序在代码中看似随机的位置崩溃:java.lang.OutOfMemoryError: GC overhead limit exceeded。如果我用谷歌搜索这个错误,我会找到this SO question,这会导致我找到this piece of sun documentation,这说明:

如果时间过长,并行收集器将抛出 OutOfMemoryError 用于垃圾收集:如果超过 98% 的总时间是 花费在垃圾收集上,只有不到 2% 的堆被回收, OutOfMemoryError 将被抛出。此功能旨在防止 应用程序在制作过程中长时间运行 由于堆太小,很少或没有进展。如有必要,这 可以通过将选项 -XX:-UseGCOverheadLimit 添加到 命令行。

这告诉我,我的应用程序显然将 98% 的总时间用于垃圾收集,只恢复了 2% 的堆。

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

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

【问题讨论】:

  • 从文档来看,这似乎是整个 2 周的 98%。您是否使用这些标志启用了 GC 日志 -verbose:gc -XX:+PrintGCDetails XX:+PrintGCTimeStamps –Xloggc:PATH_FROM_ROOT/gclog.log。很高兴看到应用程序运行时间和由于 GC 而停止的时间。
  • GC 日志记录是一个不错的建议,我会尝试的。 98% 的 2 周似乎不太可能,但你是对的,这就是文档所暗示的。我希望这只是不精确的写作
  • 你找到98%时间的含义了吗?我的观点是,GC 应该在异常发生的那一刻忙于占用 98% 的应用程序利用率,而不是在 2 周内。
  • @Monis:我还没找到,放弃找了。 98% 的时间“在这一刻”没有多大意义,因为从定义上看,一个时刻不是一段时间,所以“98% 的时刻”也不可能是(而且和“长”一样2% 的时间)。

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


【解决方案1】:

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

嗯,你使用了太多的内存 - 从它的声音来看,这可能是因为缓慢的内存泄漏。

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

要调查是否是内存泄漏,请使用 -XX:+HeapDumpOnOutOfMemoryError 开关指示 VM 在 OOM 上转储堆,然后分析堆转储以查看某种对象是否超过应有的数量。 http://blogs.oracle.com/alanb/entry/heap_dumps_are_back_with 是一个不错的起点。


编辑: 就像命运一样,我碰巧在提出这个问题的第二天,在一个批处理式应用程序中遇到了这个问题。这不是由内存泄漏引起的,增加堆大小也无济于事。我所做的实际上是减少 堆大小(从 1GB 到 256MB)以使完整的 GC 更快(尽管更频繁)。 YMMV,但值得一试。

编辑 2: 并非所有问题都可以通过较小的堆解决...下一步是启用 G1 garbage collector,这似乎比 CMS 做得更好。

【讨论】:

  • 我正在尝试一些分析,我也会尝试那个。谢谢。
  • 我走的路线和你类似,试验了参数。最终,增加堆大小和对我的代码进行一些调整(虽然我没有发现内存泄漏)似乎解决了我的问题。
  • 为什么要在批处理式应用程序中使用 CMS 或 G1?吞吐量收集器不是更好吗?
【解决方案2】:

>98% 将在不到 2% 的内存被恢复的同一时期测量。

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

添加-XX:-UseGCOverheadLimit 很可能无法“解决”您的问题。最有可能的结果是,您的应用程序将缓慢爬行,使用更多内存,然后到达 GC 不再恢复 任何 内存的地步。相反,修复您的内存泄漏,然后(如果仍然需要)增加您的堆大小。

【讨论】:

    【解决方案3】:

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

    简单的答案是没有指定。但是,在实践中,启发式“有效”,因此它不可能是您提出的两种极端解释中的任何一种。

    如果您真的想知道进行测量的时间间隔,您可以随时阅读 OpenJDK 6 或 7 源代码。但我不会打扰,因为它不会帮助你解决你的问题。

    “最好”的方法是阅读调优方面的内容(从 Oracle / Sun 页面开始),然后仔细“调整调优旋钮”。这不是很科学,但考虑到当前可用的工具,问题空间(准确地预测应用程序 + GC 性能)“太难”了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-21
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多