JVM 内存泄漏排查与解决指南(实战 + 工具 + 方法)
在 Java 中有 GC(垃圾回收),但这并不意味着不会发生内存泄漏。
很多线上问题其实不是 OOM 本身,而是:
内存一直涨,最终导致 OOM
本文将系统讲清:
- 什么是 JVM 内存泄漏
- 如何判断是否发生泄漏
- 完整排查流程(非常重要)
- 常用工具(实战)
- 常见泄漏场景与解决方案
一、什么是内存泄漏?
👉 定义:
text
对象已经"没用",但仍然被引用,导致无法被 GC 回收
👉 本质:
text
该释放的内存没有释放
二、如何判断是否发生内存泄漏?
🚨 典型表现:
text
1. 内存持续增长(不会下降)
2. Full GC 后内存仍然很高
3. 最终触发 OOM
📊 关键判断标准:
text
GC 后内存是否回落
👉 如果:
- GC 后内存下降 → 正常
- GC 后内存不降 → 可能泄漏
三、排查流程(核心)
👉 记住这个流程,比背工具更重要:
🧭 Step 1:确认问题
text
查看内存曲线(是否持续增长)
工具:
- JConsole
- VisualVM
🧭 Step 2:触发 GC 观察
text
手动 GC,看内存是否下降
👉 不下降 → 高概率泄漏
🧭 Step 3:生成堆快照(Heap Dump)
bash
jmap -dump:format=b,file=heap.hprof <pid>
或 JVM 参数:
bash
-XX:+HeapDumpOnOutOfMemoryError
🧭 Step 4:分析 Heap Dump
👉 使用工具:
- Eclipse MAT(最常用)
- VisualVM
👉 重点看:
text
1. 哪些对象最多(占用内存大)
2. 谁在引用它(GC Roots 路径)
🧭 Step 5:定位代码
👉 找:
text
是谁"持有引用不释放"
🧭 Step 6:修复问题
👉 删除不必要引用 / 优化数据结构
四、常用工具详解
1️⃣ jmap(导出堆)
bash
jmap -dump:format=b,file=heap.hprof <pid>
👉 用于:
- 导出堆内存快照
2️⃣ jstat(查看 GC)
bash
jstat -gc <pid> 1000
👉 用于:
- 查看 GC 情况
- 判断内存变化趋势
3️⃣ jstack(线程分析)
bash
jstack <pid>
👉 用于:
- 分析线程是否导致资源占用
4️⃣ VisualVM(推荐)
👉 功能:
- 实时监控内存
- 导出 Heap Dump
- 查看对象分布
5️⃣ Eclipse MAT(最强分析工具)
👉 核心功能:
text
Dominator Tree(支配树)
Leak Suspects(泄漏分析)
👉 用它可以直接找到:
text
哪个对象"占住了内存"
五、常见内存泄漏场景
❗ 1. 集合未清理
java
List<Object> list = new ArrayList<>();
while (true) {
list.add(new Object());
}
👉 问题:
text
集合一直持有引用 → 永远不会释放
❗ 2. 静态变量持有对象
java
static List<Object> cache = new ArrayList<>();
👉 特点:
text
生命周期 = JVM 生命周期
❗ 3. 线程池未关闭
👉 问题:
text
线程一直存在 → 引用一直存在
❗ 4. Listener / 回调未释放
👉 常见于:
- GUI
- 事件系统
❗ 5. ThreadLocal 泄漏(高频面试点)
👉 原因:
text
ThreadLocalMap key 被回收,
但 value 仍然存在
👉 解决:
java
threadLocal.remove();
❗ 6. 类加载器泄漏(服务器常见)
👉 场景:
- Tomcat 热部署
- 动态加载类
六、如何解决内存泄漏?
✅ 通用方法:
text
1. 清理无用引用
2. 控制集合大小
3. 使用弱引用(WeakReference)
4. 正确关闭资源(线程、连接)
✅ 技术手段:
- 使用缓存淘汰策略(LRU)
- 避免无限增长的数据结构
- 合理设计生命周期
七、一个完整实战思路(重要)
text
发现内存上涨
→ GC 后不下降
→ 导出 heap dump
→ MAT 分析
→ 找最大对象
→ 查 GC Roots
→ 定位代码
→ 修复引用
八、面试高频问题
✔ 什么是内存泄漏?
👉 有引用但无用对象无法被回收
✔ 如何排查?
👉 Heap Dump + MAT 分析
✔ 常用工具?
text
jmap / jstat / jstack / VisualVM / MAT
✔ 如何判断?
👉 GC 后内存是否下降
九、终极总结
text
内存泄漏本质:
"引用没断"
再补一句更实战的:
text
排查核心:
找谁在"持有引用不放"
十、结语
JVM 内存泄漏不是理论问题,而是真实生产问题:
- 会导致系统变慢
- 会导致 OOM
- 会导致服务崩溃
掌握排查方法,比背概念更重要。
如果你能熟练使用 MAT + Heap Dump,你已经具备线上排查能力。