

获取JVM堆内存转储的常用方法
source link: https://renfufei.blog.csdn.net/article/details/108785603
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1. 堆内存转储简介
堆内存转储(Heap Dump),是指JVM堆内存在某一个时刻的快照,一般使用 hprof
格式的二进制文件来保存。 可用于分析内存泄漏问题,以及Java程序的内存使用优化。
常见的内存转储分析工具包括: jhat, JVisualVM, 以及基于Eclipse的 MAT工具.
下面介绍获取堆内存转储的常用方法。
2. 使用JDK内置工具
JDK内置了很多诊断工具,位于 JDK_HOME/bin
目录下,一般来说这个目录可以包含到系统PATH路径中,可以直接在命令行中调用。
JDK内置的堆内存转储工具包括:
2.1 jmap
工具
jmap
可用来输出JVM内存的统计信息,支持访问本地JVM,以及远程JVM实例。
使用 -dump
选项来获取堆内存转储,命令为:
jmap -dump:[live],format=b,file=<file-path> <pid>
在 -dump:
选项后面, 可以指定以下参数:
live
: 可选参数;表示只输出存活对象,也就是会先执行一次FullGC来清除可以被回收的部分。format=b
: 可选参数, 指定 dump 文件为二进制格式(binary format). 在堆内存转储时,默认就是二进制格式。file
: 指定转储文件的保存路径。pid
: 指定Java进程的pid。
使用示例如下:
jmap -dump:live,format=b,file=/tmp/dump.hprof 12587
# 或者
jmap -dump:file=/tmp/dump.hprof 12587
JVM进程的 pid 一般是通过 jps
命令获取,当然也可以使用通过 jcmd
命令,或者 ps
命令查询。
2.2 jcmd
工具
jcmd
是一个全能的命令行诊断工具,其工作原理是将要执行的命令发送给具体的JVM实例,所以只支持在本地机器上使用。
其中的一个命令是 GC.heap_dump
, 可以用来获取堆内存转储,只需要指定 pid 即可,命令格式为:
jcmd <pid> GC.heap_dump <file-path>
使用示例也类似:
jcmd 12587 GC.heap_dump /tmp/dump.hprof
和 jmap 一样,内存转储文件都是二进制的。
因为是把命令当做参数传给具体的JVM来执行,所以文件路径最好是绝对路径。
2.3 JVisualVM 工具
JVisualVM是一款图形界面工具,可用来监控、分析和诊断Java应用程序。

图形界面简单优雅,而且功能强大,支持众多插件。
其中的一个功能是抓取堆内存快照,打开程序,在可见的Java进程上点击鼠标右键,选择“堆内存转储(Heap Dump)”, 即可创建新的内存转储文件,并自动在新标签页中打开。

完成之后,我们可以在基本信息(Basic Info)中看到转储文件的目录信息。
3. 自动执行堆内存转储
前面介绍的工具都是手工执行的,有时候,我们希望在发生内存溢出错误 java.lang.OutOfMemoryError
时, JVM自动执行堆内存转储,以方便事后进行排查和分析。 JVM提供了一个命令行启动参数 HeapDumpOnOutOfMemoryError
, 使用的格式为:
java -XX:+HeapDumpOnOutOfMemoryError
如果不用 HeapDumpPath
选项指定转储路径,则会自动保存到启动目录下,文件名的格式为: java_pid<pid>.hprof
。
指定 HeapDumpPath
参数的使用示例如下:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-or-dir-path>
Java程序在运行过程中如果发生内存溢出,则会在日志中看到类似这样的内容:
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Dumping heap to java_pid12587.hprof ...
Exception in thread "main" Heap dump file created [4744371 bytes in 0.029 secs]
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at com.baeldung.heapdump.App.main(App.java:7)
这里自动创建的转储文件名称为 java_pid12587.hprof
。
可以看到,这个选项非常有用,而且对正常运行的程序来说没有什么开销。 因此强烈建议开启该选项,特别是在生产环境中。
当然,这个选项也可以通过 HotSpotDiagnostic
MBean 来动态设置,比如在JMX客户端之中设置 HeapDumpOnOutOfMemoryError
选项的值为 true
:

MBeans 和 JMX 的更多信息请参考: JMX 与相关工具:山高月小,水落石出
4. JMX方式
最后,我们来看看怎么通过JMX方式获取堆内存转储。 本质上是调用 HotSpotDiagnostic
这个MBean,其提供了一个 dumpHeap
方法, 参数为:
outputFile
: 转储文件的路径, 一般以.hprof
后缀结尾。live
: 如果设置为true
, 则只转储存活对象, 和jmap
的使用类似。
下面是使用示例:
4.1. JMX客户端工具
HotSpotDiagnostic
MBean 最容易操作的方式是图形界面客户端, 例如 JConsole
, JVisualVM
等。
打开 JConsole
, 连接到指定的Java进程, 切换到 MBeans
页签, 定位到 com.sun.management.
包下面的 HotSpotDiagnostic
, 执行对应的 dumpHeap
方法即可。

然后在 p0
和 p1
槽位填写对应的参数 outputFile
, live
, 执行 dumpHeap
即可。
4.2. 编程方式调用
首先,需要获取 MBeanServer
实例,然后再获取系统注册的 HotSpotDiagnosticMXBean
MBean, 接着调用 dumpHeap
方法, 示例代码如下:
public static void dumpHeap(String filePath, boolean live) throws IOException {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(
server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
mxBean.dumpHeap(filePath, live);
}
请注意 hprof
文件不能被覆盖, 如果文件已存在,则会报错:
Exception in thread "main" java.io.IOException: File exists
at sun.management.HotSpotDiagnostic.dumpHeap0(Native Method)
at sun.management.HotSpotDiagnostic.dumpHeap(HotSpotDiagnostic.java:60)
本文介绍了几种获取堆内存转储的方法。 简单总结一下:
- 强烈建议指定JVM启动参数
HeapDumpOnOutOfMemoryError
. - 如果
jmap
不能使用,可以使用其他的替代方式,例如 jcmd、JVisualVM、JMX等等。 - 本文对应的代码请参考: GitHub仓库.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK