JVM Dump 是故障定位、性能调优、内存泄漏、死锁分析的核心依据,主要分两大类:线程快照 (Thread Dump)、堆快照 (Heap Dump),下面从概念、场景、生成、分析、实战逐一讲解。
一、基础概念区分
1. Thread Dump(线程转储 / 线程快照)
- 定义:某一时刻 JVM 内所有线程的运行状态、调用栈、锁信息的文本快照。
- 作用:排查死锁、线程阻塞、线程池耗尽、CPU 飙高、接口卡顿、死循环。
- 格式:纯文本,体积小、生成快,可多次连续抓取。
2. Heap Dump(堆转储 / 堆快照)
- 定义:某一时刻 JVM整个堆内存(新生代、老年代、元空间除外)的对象实例、引用关系、对象大小、类信息的二进制文件。
- 作用:排查内存泄漏、OOM、堆内存溢出、大对象、内存占用过高。
- 格式:二进制
.hprof文件,体积和堆内存一致,大堆生成 / 分析较慢。
补充:还有GC Dump(GC 日志)、JFR 飞行日志,不属于传统 Dump,是辅助调优手段。
二、Thread Dump 线程快照(重点:线程问题排查)
1. 线程状态(核心识别点)
JVM 线程常见 6 种状态,Dump 中关键字对应:
- RUNNABLE:可运行 / 正在执行(CPU 繁忙、死循环多为此状态)
- BLOCKED:被锁阻塞(等待 synchronized 锁,典型死锁场景)
- WAITING:无限等待(
wait()/join(),主动休眠等待唤醒) - TIMED_WAITING:限时等待(
sleep()、wait(time)、线程池空闲线程) - TERMINATED:线程已结束
- NEW:线程未启动
2. 生成 Thread Dump 的 4 种常用方式
前提:先拿到Java 进程 PID
# 查Java进程PID jps -l # 或 ps -ef | grep java方式 1:jstack(最常用,JDK 自带)
# 单次输出到控制台 jstack 进程PID # 输出到文件(推荐) jstack PID > thread_dump_$(date +%Y%m%d%H%M).log # 连续抓取3次(间隔2秒,排查瞬时卡顿/死循环) jstack PID > td1.log sleep 2 jstack PID > td2.log sleep 2 jstack PID > td3.log方式 2:kill -3(Linux 原生,不杀进程)
kill -3 PID- 不会终止进程,线程栈直接输出到 JVM 标准错误流(Tomcat/Java 容器一般输出到
catalina.out、nohup.out)。
方式 3:Arthas(线上首选,无侵入)
线上生产环境优先用 Arthas,无需重启:
# 进入arthas as # 查看所有线程栈 thread # 查看指定线程栈 thread 线程ID # 一键导出全量线程dump thread -all > /tmp/thread.log方式 4:JVisualVM / JConsole(图形化,本地测试)
可视化工具直接点击「线程→线程 Dump」,适合开发环境。
3. 典型问题 & 解读案例
(1)死锁 Deadlock
Dump 末尾会明确提示Found 1 deadlock.,同时标注两个线程互相持有对方锁。现象:接口卡死、服务不响应、线程大量 BLOCKED。
(2)CPU 100%(线程死循环)
排查步骤:
top -Hp PID找到占用 CPU 最高的线程 TID(十进制)- 转十六进制:
printf "%x\n" 十进制TID jstack PID搜索十六进制线程 ID,定位死循环代码行。
(3)线程池耗尽、任务堆积
大量线程处于WAITING,栈帧卡在线程池getTask(),说明任务提交速度 > 处理速度。
三、Heap Dump 堆快照(重点:内存泄漏、OOM)
1. 触发时机 & 应用场景
适用场景:
- 应用抛出
java.lang.OutOfMemoryError: Java heap space堆溢出 - 内存持续上涨、Full GC 频繁、GC 后内存不释放(内存泄漏)
- 排查大对象、大集合、静态集合常驻内存
2. 生成 Heap Dump 的 5 种方式
方式 1:OOM 自动生成(生产必配JVM 参数)
发生 OOM 时自动 dump 堆,事后溯源最有效,无需人工干预。
# JDK8 常用配置 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/jvm/dump/heap_dump.hprof参数说明:
+HeapDumpOnOutOfMemoryError:OOM 时自动生成堆快照HeapDumpPath:指定 dump 文件路径(建议独立磁盘,避免占满分区)
注意:堆多大,文件就多大,大堆 (8G/16G) 生成会卡顿,短暂影响业务。
方式 2:jmap(JDK 自带命令,手动抓取)
# 1. 导出整个堆(包含所有对象,完整分析,推荐) jmap -dump:format=b,file=/tmp/heap.hprof PID # 2. 只导出存活对象(忽略已死对象,文件更小) jmap -dump:live,format=b,file=/tmp/heap_live.hprof PID # 3. 查看堆概览(先看整体,不用分析大文件) jmap -heap PID风险提醒
jmap会触发STW(Stop-The-World),堆越大、停顿越久。- 生产大堆(>4G)不建议频繁执行,优先用 Arthas / JFR。
方式 3:Arthas(线上低侵入抓取,推荐生产)
# 进入arthas后,导出堆快照 heapdump --live /tmp/heap.hprof--live:只导出存活对象,体积更小、速度更快。
方式 4:JVisualVM / JConsole 图形化
本地测试、测试环境使用,界面点击「堆 Dump」即可。
方式 5:JVM 启动参数 -XX:+DumpHeapBeforeFullGC
每次 Full GC 前自动 dump,用于排查频繁 Full GC。
3. 关键 JVM 参数补充(Dump 相关)
# 限制dump文件大小、压缩等(可选) -XX:+HeapDumpCompressionLevel=1 # 压缩hprof,减小体积 -XX:HeapDumpTimeout=300 # dump超时时间4. Heap Dump 核心分析工具
(1)MAT(Eclipse Memory Analyzer,行业标准)
- 开源、功能最强,专门分析
.hprof - 核心功能:泄漏可疑报告、对象直方图、支配树、线程栈、引用链
- 用法:打开 hprof 文件 → 选择Leak Suspects(泄漏疑点)一键分析。
(2)JVisualVM
JDK 自带,轻量,适合简单分析、本地调试。
(3)JProfiler
商业工具,可视化强,付费,企业常用。
(4)在线工具(小文件临时分析)
如 HeapHero,适合几 G 以内小堆快速查看。
5. 堆 Dump 核心分析思路(调优实战流程)
看直方图(Histogram)按类统计对象数量、占用内存,找出实例数异常多、单类占比极高的类。
查大对象 / 大集合定位
ArrayList/HashMap等集合无限膨胀、未释放。分析引用链(Reference Chain)找到「谁持有这个对象的引用」—— 内存泄漏本质:对象本该被 GC,却被强引用一直持有。 常见泄漏点:
- 静态集合(
static List)不断 add 不 clear - 线程池、ThreadLocal 未手动 remove
- 数据库连接、IO 流、缓存未关闭 / 过期
- 第三方框架内存泄漏
- 静态集合(
查看类加载 & 元空间区分是堆溢出还是元空间溢出(Metaspace OOM)。
四、Thread Dump vs Heap Dump 选型(什么时候用哪个?)
| 现象 | 优先使用 | 典型问题 |
|---|---|---|
| CPU 持续 100%、接口超时、卡死 | Thread Dump | 死循环、死锁、线程阻塞 |
| OOM 报错、内存持续上涨、Full GC 频繁 | Heap Dump | 内存泄漏、大对象、堆溢出 |
| 服务间歇性卡顿、偶发超时 | 两者结合 | 线程阻塞 + 内存波动 |
五、线上生产最佳实践(避坑)
- 必配 OOM 自动 Dump 参数线上所有 Java 应用强制加上
HeapDumpOnOutOfMemoryError,出问题才有溯源依据。 - Dump 文件单独挂载磁盘避免堆很大时,dump 文件占满系统盘导致服务宕机。
- 大堆慎用 jmap -dump8G+ 堆优先用 Arthas 抓取,减少 STW 停顿。
- 抓取策略
- 线程问题:连续抓 2~3 份 Thread Dump(间隔 2s)对比状态。
- 内存问题:GC 高峰期抓取 Heap Dump,优先加
--live。
- Dump 文件及时清理hprof 文件体积巨大,分析完立即删除。
六、常见问题答疑
- Dump 文件打不开 / 分析卡顿?
- 增大 MAT/JVisualVM 的启动堆内存(修改
mat.ini加大-Xmx)。
- 增大 MAT/JVisualVM 的启动堆内存(修改
- 多次 Dump 内容不一样正常吗?正常,线程、对象状态是动态变化的。
- live 和不 live 区别?
live只保留存活对象,文件小、分析快;不带 live 包含垃圾对象,适合完整复盘。 - STW 影响业务怎么办?低峰期抓取,或使用 JFR(Java Flight Recorder)替代,几乎无停顿。