【问题标题】:Java 8 JVM hangs, but does not crash/ heap dump when out of memoryJava 8 JVM 挂起,但在内存不足时不会崩溃/堆转储
【发布时间】:2019-02-20 07:34:11
【问题描述】:

内存不足时,运行 Tomcat 8 的 Java 8 在堆转储后永远不会停止。相反,它只是挂起,因为它最大内存。由于广泛的 GC,服务器变得非常缓慢且无响应,因为它慢慢接近最大内存。达到最大值后,JConsole 中的内存图呈扁平线。 64位linux/java版本“1.8.0_102”/Tomcat 8.Jconsole

我设置了 -XX:HeapDumpOnOutOfMemoryError 和 -XX:HeapDumpPath。任何人都知道如何强制堆转储而不是 JVM 进入无响应/非常慢的响应模式?

【问题讨论】:

  • 你真的看到OOM了吗?
  • 我没有看到 OOM。 JVM 的响应速度越来越慢,最终没有响应。
  • -XX:HeapDumpOnOutOfMemoryError 似乎不对,您是否尝试过 `-XX:+HeapDumpOnOutOfMemoryError' (列后带有 '+' )?此 JVM 选项是一个开关,因此您可以分别使用“+”或“-”启用/禁用它。
  • 对不起,我正在使用 XX:+HeapDumpOnOutOfMemoryError。
  • 也许尝试使用 jmap 在内存不足之前创建堆转储? docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/…

标签: java jvm heap-dump


【解决方案1】:

任何人都知道如何强制堆转储而不是 JVM 进入无响应/非常慢的响应模式?

您需要使用-XX:+UseGCOverheadLimit。这告诉 GC 在垃圾收集所花费的时间百分比太高时抛出 OOME(或转储堆,如果您已配置)。这应该默认为最近的 JVM 启用...但您可能已禁用它。

您可以使用-XX:GCTimeLimit=...-XX:GCHeapFreeLimit=... 调整收集器放弃的“开销”阈值;见https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc-ergonomics.html

“开销”限制的影响是您的应用程序更早地获得了 GC 失败。希望这可以避免“死亡螺旋”效应,因为 GC 使用越来越多的时间来收集越来越少的实际垃圾。

另一种可能性是您的 JVM 需要很长时间来转储堆。如果真正的问题是您的 JVM 导致虚拟内存抖动,因为 Java 的内存使用量明显大于物理内存量,则可能会发生这种情况。

【讨论】:

  • UseGCOverheadLimit 默认设置为 true。但是,它使我调查了其他 JVM 选项 java -XX:+PrintFlagsFinal -version | grep -i 内存。 ExitOnOutOfMemoryError 默认为 false。这就解释了为什么 JVM 没有退出。我尝试更改 GCTimeLimit 和 GCHeapFreeLimit 并没有效果
  • 我链接到的文档暗示 GCLimit 参数可能仅适用于 Parallel 收集器。我只是一个但不清楚...
【解决方案2】:

jmap 是为任何正在运行的 jvm 创建堆转储的实用程序。这将允许您在崩溃之前创建堆转储

https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr014.html

不过,知道何时创建它只是时间问题。您可以获取后续堆并使用工具来比较堆。我强烈推荐 Eclipse 内存访问工具和它的支配树视图来识别潜在的内存问题 (https://www.eclipse.org/mat/)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-28
    • 2019-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多