jmap 可能因权限不匹配、attach 被禁用或磁盘空间不足而失败;应使用 jmap -dump:format=b,file=xxx.hprof 导出二进制堆转储,避免 live 参数;推荐预设 -XX:+HeapDumpOnOutOfMemoryError 自动触发,并用 MAT 分析,注意调大其堆内存。

确认 jmap 是否可用且目标进程有权限
线上 OOM 后 JVM 往往已处于半挂起状态,jmap 可能无法 attach 到进程,或因权限不足被拒绝。常见报错:java.lang.AttachNotSupportedException: Unable to open socket file 或 Permission denied。
必须确保:
- 执行 jmap 的用户与启动 Java 进程的用户**完全一致**(不能用 root 去 dump 普通用户启的进程)
- 目标 JVM 是 HotSpot 且未禁用 attach 功能(JDK 8+ 默认开启,但若加了 -XX:+DisableAttachMechanism 就彻底不可用)
- /tmp 或 /proc/ 下有足够磁盘空间(堆转储文件大小 ≈ 当前堆占用,可能数 GB)
用 jmap -dump:format=b,file=xxx.hprof 最小化干扰导出
不要用 jmap -histo 或 jmap -heap 代替 dump —— 它们不生成可分析的堆镜像,对定位 OOM 根本没用。真正要的是二进制 .hprof 文件。
推荐命令(务必加 format=b):jmap -dump:format=b,file=/data/logs/heap_$(date +%s).hprof
- format=b 表示 binary 格式,是 MAT/Eclipse Memory Analyzer 唯一支持的格式
- 避免用 live 参数(如 -dump:live,format=b,...),它会触发 Full GC,可能让正在 OOM 崩溃的进程雪上加霜
- 不要在生产高峰执行;如果进程已卡死,jmap 可能阻塞几十秒甚至更久,影响服务可用性
导出失败时的替代方案:JVM 启动参数预埋
等 OOM 发生再手动 dump,往往错过最佳时机。更可靠的做法是在启动时就配置自动 dump:
在 Java 启动参数中加入:-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/data/logs/heap_oom.hprof-XX:+PrintGCDetails
- HeapDumpOnOutOfMemoryError 会在 OOM 异常抛出后立即写入堆转储,此时堆状态最接近问题现场
- HeapDumpPath 支持时间戳占位符,如 /data/logs/heap_%p_%t.hprof(%p 是 pid,%t 是时间戳)
- 注意:该机制只对 java.lang.OutOfMemoryError: Java heap space 生效,对 Metaspace 或 Direct buffer memory 类型的 OOM 无效
导出后的文件别直接用 vim 打开
.hprof 是二进制文件,用文本工具打开只会看到乱码,还可能因加载过大导致终端假死。正确做法是下载到本地后用专业工具分析:
- 推荐优先用 Eclipse Memory Analyzer (MAT):开源、轻量、对大堆(>4GB)支持好,能快速生成 Leak Suspects Report
- 若堆极大(>16GB),可先用 jhat(已废弃但还能用)或 VisualVM 做粗筛,再用 MAT 深挖
- 不要用 jdk/bin/jhat 在生产机上直接运行:它会起 HTTP 服务并吃光内存和 CPU
一个容易被忽略的点:MAT 默认堆内存只有 1024MB,分析 8GB 堆转储前,务必修改 MemoryAnalyzer.ini 中的 -Xmx 参数,否则直接 OOM 退出。









