jcmd 推荐用于导出堆转储,因其通过 JVM 内部命令通道工作,不依赖 attach 机制,对高负载应用干扰极小;执行 jcmd JAVA_PID GC.heap_dump /path/to/heap.hprof 即可,需确保路径可写且磁盘空间充足。

用 jcmd 导出堆转储(推荐,影响小)
OpenJDK 7u40+ 默认自带 jcmd,它通过 JVM 内部命令通道工作,不依赖外部 attach 机制,对运行中应用的干扰远小于 jmap。实测在高负载服务上执行几乎无感知停顿。
操作分两步:
- 查进程 ID:
jps -l或pgrep -f "java.*YourApp" - 触发导出:
jcmd JAVA_PID GC.heap_dump /path/to/heap.hprof
注意:JAVA_PID 必须是目标 Java 进程的真实 PID;/path/to/heap.hprof 要确保目录可写,且磁盘空间充足(堆越大,文件越大)。如果路径含空格或特殊字符,需加引号。
jmap -dump 还能用吗?风险在哪
能用,但不建议在生产环境对关键服务使用。因为 jmap 会强制 JVM 暂停所有线程(STW),直到 dump 完成——这个时间取决于堆大小和 I/O 速度,几十 GB 堆可能卡住数秒甚至更久。
常见误操作:
- 漏写
format=b:默认不生效,必须显式指定,如jmap -dump:format=b,file=heap.hprof JAVA_PID - 没加
live参数却想只 dump 存活对象:不加live会包含已标记为待回收但尚未清理的对象,分析时干扰大 - 在容器里执行失败:因容器默认禁用
ptrace,jmap会报Unable to open socket file;而jcmd通常不受此限
OOM 自动触发堆转储怎么配
这是最稳妥的兜底手段,适合长期运行、无法随时人工干预的服务。只需在启动 JVM 时加两个参数:
-
-XX:+HeapDumpOnOutOfMemoryError:开启自动 dump -
-XX:HeapDumpPath=/var/log/myapp/heap.hprof:指定路径(注意是**文件路径**,不是目录;若写成目录,JVM 会自动生成java_pid文件).hprof
关键细节:
- 路径必须存在且可写,否则 dump 失败且无提示,只会默默跳过
- 如果
HeapDumpPath指向一个已存在的文件(比如固定名heap.hprof),后续 OOM 会直接覆盖,旧 dump 丢失 - OpenJDK 17+ 支持
-XX:HeapDumpPath=/var/log/myapp/heap_%p.hprof,%p替换为 PID,避免覆盖
导出后文件打不开?先确认格式和工具兼容性
OpenJDK 生成的 .hprof 是标准 HPROF 二进制格式,但不同 JDK 版本间存在细微差异。常见问题:
- MAT 报 “Unrecognized format version”:说明 MAT 版本太老,不支持新 JDK 的 HPROF 扩展字段;升级到 MAT 1.12+(适配 JDK 17/21)
- JVisualVM 提示 “Not a valid heap dump”:检查是否误用了 JFR 录制文件(
.jfr)或线程 dump(.txt)当成了 heap dump - 文件只有几 KB:大概率导出失败或进程已退出,检查命令返回值和目标路径权限
真正要小心的是:堆转储本身不解决泄漏,只是快照。拿到 .hprof 后,必须结合 GC 日志、对象分配热点、引用链深度一起看——单看直方图容易把缓存大对象当成泄漏源。











