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

时间:2013-12-30 03:12:21

标签: java memory heap jmap

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

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

有没有办法在不挂起应用程序的情况下获取堆转储,或者是否有除jmap之外的实用程序来收集堆转储。

对此高度赞赏的想法,因为没有得到内存使用的趋势,很难解决这个问题。

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

谢谢, 阿伦

5 个答案:

答案 0 :(得分:7)

尝试以下方法。它带有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转储要快得多! Dumpfiles要小得多,但它足以让你的想法,泄漏的地方。

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

答案 1 :(得分:2)

首先,在进行线程转储/快照时冻结JVM至关重要(AFAIK)。如果JVM能够在创建快照时继续运行,那么几乎不可能获得连贯的快照。

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

  • 您可以按照here所述使用VisualVM获取堆转储。

  • 您可以使用jconsole或Eclipse Memory Analyzer获取堆转储,如here所述。

但所有这些必然导致JVM(至少)暂停。


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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

要添加到Stephen的答案,您还可以通过API为最常见的JVM实现触发堆转储:

答案 4 :(得分:0)

使用正确的工具进行分析的堆转储将确切告诉您正在消耗堆的内容。它是跟踪内存泄漏的最佳工具。但是,收集堆转储很慢,更不用说对其进行分析了。

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

这是收集直方图的命令。

jcmd pid GC.class_histogram filename=histogram.txt