最稳妥方式是执行jmap -dump:format=b,file=/tmp/heap.hprof <pid>,需确保权限、路径、JVM未禁用Attach机制,并注意STW影响及MAT兼容性问题。

怎么用 jmap 导出正在运行的 Java 进程堆快照
直接执行 jmap -dump:format=b,file=heap.hprof <pid> 是最常用也最稳妥的方式。注意必须用目标 Java 进程的 PID,不是主类名或进程名;如果权限不够(比如用普通用户启的服务,但你用 root 执行 jmap),会报 Unable to open socket file 或 attach failed —— 这时候得换到启动该 Java 进程的同一用户下操作。
常见错误现象:jmap 卡住不动、输出空文件、或者提示 java.lang.OutOfMemoryError: unable to create new native thread(说明 JVM 已严重卡顿,jmap 自身也抢不到线程资源)。
-
-dump:format=b必须写全,不能简写成-dump:b,否则可能静默失败 - 路径最好用绝对路径,比如
/tmp/heap.hprof,避免因工作目录不一致导致文件生成在意外位置 - 如果 JVM 启动时加了
-XX:+DisableAttachMechanism,jmap会彻底失效,只能靠-XX:+HeapDumpOnOutOfMemoryError预埋机制
jmap 导出的 .hprof 文件为什么 MAT 打不开或报错
Eclipse MAT 默认只认标准格式的堆转储,而 jmap 在某些 JDK 版本(尤其是 JDK 8u292+ 和 JDK 11+)默认导出的是“带压缩”的 gzip 格式(实际是 zlib 压缩流),MAT 旧版本(如 1.10.x)无法自动解压,会直接报 Invalid header 或 Unsupported HPROF version。
- 解决办法:加
-XX:+UseG1GC并不改变格式,真正有效的是加-XX:-UseCompressedOops(仅调试用)或换用jmap -dump:format=b,live,file=heap.hprof <pid>中的live参数——它会触发 GC 再 dump,同时绕过部分压缩逻辑 - 更可靠的做法:用
jcmd <pid> VM.native_memory summary确认 JVM 版本,再对应下载 MAT 支持该版本的 release(比如 JDK 17 推荐用 MAT 1.13+) - 别用文本编辑器打开
.hprof文件验证——它是二进制,开头几个字节是JAVA PROFILE 1.0或类似标识,但肉眼难辨,直接丢给 MAT 更省事
MAT 分析时“Dominator Tree”里对象数量对不上代码里的 new 次数
这不是 MAT 出错,而是因为 Dominator Tree 只统计“被该对象独占引用”的内存,不是所有 new 出来的实例都会出现在这里。比如一个 ArrayList 被多个地方引用,它的数组元素可能分散在不同 dominator 路径下;又或者对象刚被创建还没被任何变量持有(比如 new Object() 后没赋值),JVM 可能根本没分配实际内存。
立即学习“Java免费学习笔记(深入)”;
- 优先看
Leak Suspects报告,它比手动翻Dominator Tree更贴近真实泄漏场景 - 对比
Histogram中的Shallow Heap和Retained Heap:前者是对象自身大小,后者才是它“拖着不放”的全部内存,泄漏判断主要看后者增长趋势 - 如果发现某个
byte[]的Retained Heap特别大,但代码里没明显大数组逻辑,大概率是String.substring()(JDK 7u6 之前)、StringBuilder缓冲区未清空,或日志框架缓存了完整请求体
生产环境用 jmap dump 堆会不会影响服务
会,而且影响不小。dump 过程需要暂停 JVM(STW),时间取决于堆大小和可用内存带宽。一个 4GB 堆在普通磁盘上可能 STW 5–10 秒,期间所有请求超时、线程阻塞、连接断开都是大概率事件。
- 绝对不要在高峰期执行
jmap -dump,哪怕加了live参数也无法消除 STW - 如果必须抓现场,优先考虑开启
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dumps,让 JVM 自己在 OOM 时 dump,代价是一次性崩溃,但不影响日常流量 - 替代方案:用
jdk.jfr(Java Flight Recorder)持续采样内存分配热点,不 STW,但只能看到“谁在频繁 new”,看不到对象图全貌
真正麻烦的不是命令怎么敲,而是 dump 文件本身可能几百 MB 到几 GB,传回本地分析前得先确认磁盘空间、网络带宽、MAT 内存配置(MemoryAnalyzer.ini 里 -Xmx 至少设为 dump 大小的 1.5 倍)——这些细节漏掉,前面所有操作都白费。










