Java:在没有jmap或挂起应用程序的情况下获取堆转储



在少数情况下,我们的应用程序使用大约12GB的内存。我们尝试使用jmap实用程序来获取堆转储。由于应用程序正在使用一些GB的内存,这会导致应用程序停止响应,并导致生产中出现问题。

在我们的案例中,堆使用量在6小时内突然从2-3GB增加到12GB。为了找到内存使用趋势,我们尝试在重新启动应用程序后每一小时收集一次堆转储。但是正如所说,由于使用jmap会导致应用程序挂起,我们需要重新启动它,并且我们无法了解内存使用的趋势。

有没有一种方法可以在不挂起应用程序的情况下获得堆转储,或者有没有jmap以外的实用程序可以收集堆转储。

对此的思考值得高度赞赏,因为如果不了解内存使用的趋势,就很难解决这个问题。

注意:我们的应用程序可在CentOS中运行。

谢谢,阿伦

尝试以下操作。它附带JDK>=7:

/usr/lib/jvm/jdk-YOUR-VERSION/bin/jcmd PID GC.heap_dump FILE-PATH-TO-SAVE

示例:

/usr/lib/jvm/jdk1.8.0_91/bin/jcmd 25092 GC.heap_dump /opt/hd/3-19.11-jcmd.hprof

这个转储过程比使用jmap转储要快得多!转储文件要小得多,但它足以让你知道泄漏的位置。

在编写此答案时,Memory Analyzer和IBM HeapAnalyzer存在错误,它们无法从jmap(jdk8,大文件)中读取转储文件。您可以使用Yourkit读取这些文件。

首先,在执行线程转储/快照时冻结JVM是(AFAIK)必不可少的。如果JVM能够在创建快照时继续运行,那么几乎不可能获得一致的快照。

那么,还有其他方法可以获得堆转储吗?

  • 您可以使用VisualVM获得堆转储,如下所述。

  • 您可以使用jconsole或Eclipse内存分析器获得堆转储,如下所述。

但所有这些都会导致JVM(至少)暂停。


如果您的应用程序实际上挂起了(永久挂起!),这听起来像是应用程序本身的问题。我的建议是,在查找存储泄漏之前,看看是否可以找到问题。

我的另一个建议是,您可以查看单个堆转储,并使用统计数据来确定哪些类型的对象正在使用所有空间。。。以及为什么它们是可访问的。很有可能你根本不需要"趋势"信息。

您可以使用GDB来获取堆转储,而无需在目标VM上运行jmap,但这仍然会在将堆转储写入磁盘所需的时间内挂起应用程序。假设磁盘速度为100MB/s(基本镜像阵列或单个磁盘),这仍然是2分钟的停机时间。http://blogs.atlassian.com/2013/03/so-you-want-your-jvms-heap/

避免停止JVM的唯一真正方法是事务内存和利用它提供进程快照功能的内核。这是STM支持者的梦想之一,但目前还没有。VMWare的热迁移很接近,但取决于您的分配速率是否超过网络带宽,而且它不会保存快照。请求他们为你添加它,这将是一个巧妙的功能。

使用正确的工具分析的堆转储将准确地告诉您是什么在消耗堆。它是追踪内存泄漏的最佳工具。然而,收集堆转储是很慢的,更不用说分析它了

了解应用程序的工作原理后,有时直方图就足以为您提供查找问题的线索。例如,如果MyClass$Inner位于直方图的顶部,而MyClass$Inner仅用于MyClass,那么您就可以确切地知道要查找哪个文件来查找问题。

这是收集直方图的命令。

jcmdpidGC.class_histogram filename=histogram.txt

为了补充Stephen的答案,您还可以通过API为最常见的JVM实现触发堆转储:

  • Oracle JVM示例
  • 用于IBM JVM的API

相关内容

最新更新