堆转储是 JVM 中特定时刻内存中的所有对象的快照。它们对于解决内存泄漏问题并优化 Java 应用程序中的内存使用情况非常有用。
堆转储通常以二进制格式 hprof 文件存储。我们可以使用 jhat 或 JVisualVM 等工具打开和分析这些文件。
下面介绍两种堆转储的方式:
1. JCMD
jcmd 是一个非常完整的工具,它通过向 JVM 发送命令请求来工作。我们必须在运行 Java 进程的同一台计算机上使用它。
其众多命令之一是 GC.heap_dump。我们只需指定进程的 pid 和输出文件路径,就可以使用它来获取堆转储:
jcmd <pid> GC.heap_dump <file-path>
例如:
[root@cwy-hbcsh-zyl-1 HDTool]# jps
22387 jar
17925 jar
13383 jar
26682 Jps
21422 jar
[root@cwy-hbcsh-zyl-1 HDTool]# jcmd 17925 GC.heap_dump /opt/HDTool/dump.hprof
17925:
Heap dump file created
[root@cwy-hbcsh-zyl-1 HDTool]#
2. 自动捕捉head dump
上面工具jcmd旨在在特定时间手动捕获堆转储。在某些情况下,我们希望在发生内存溢出错误 java.lang.OutOfMemoryError 时, JVM自动执行堆内存转储,以方便事后进行排查和分析。
JVM提供了一个命令行启动参数 HeapDumpOnOutOfMemoryError, 使用的格式为:
java -XX:+HeapDumpOnOutOfMemoryError
- 如果不用 HeapDumpPath 选项指定转储路径,则会自动保存到启动目录下,文件名的格式为:
java_pid<pid>.hprof
- 指定 HeapDumpPath 参数的使用示例如下:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-or-dir-path>
对于某个应用服务,启动脚本中设置内存溢出转储路径为/opt/logs/app。如下:
特别说明:不建议内存溢出文件名写死,建议只写路径;否则,再次发生内存溢出,内存溢出文件无法成功保存。
如下:文件命名为heapdump.hprof,下次发生内存溢出,再次生成的heapdump.hprof无法保存。
无法保存的提示如下:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to /opt/logs/app/heapdump.hprof ...
Unable to create /opt/logs/app/heapdump.hprof: 文件已存在