获取JVM堆内存转储的常用方法
Posted 铁锚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了获取JVM堆内存转储的常用方法相关的知识,希望对你有一定的参考价值。
文章目录
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)
5. 小结
本文介绍了几种获取堆内存转储的方法。 简单总结一下:
- 强烈建议指定JVM启动参数
HeapDumpOnOutOfMemoryError
. - 如果
jmap
不能使用,可以使用其他的替代方式,例如 jcmd、JVisualVM、JMX等等。 - 本文对应的代码请参考: GitHub仓库.
以上是关于获取JVM堆内存转储的常用方法的主要内容,如果未能解决你的问题,请参考以下文章
JVM --------jmap-----查看堆内存信息生成heap dump 文件(转储堆内存快照到指定文件)