掌握JVM内存泄漏排查需建立“生命周期错配→现象识别→精准定位→代码修复”闭环思维:一盯老年代阶梯上涨、新生代晋升增加、Metaspace单边增长三类曲线;二用“生命周期四象限”分析持有关系;三熟记静态集合、ThreadLocal、资源未关闭三大高频泄漏点及修复方案;四动手实操jstat、jmap、MAT全流程验证。

掌握JVM内存泄漏排查,关键不是背工具命令,而是建立“生命周期错配→现象识别→精准定位→代码修复”的闭环思维。下面四点直击复习核心:
一、先盯住三类典型内存曲线形态
线上监控第一眼要看的不是数字高低,而是变化趋势:
- 老年代阶梯式上涨:每次Full GC后回落幅度越来越小 → 高概率是静态缓存、未注销监听器、ClassLoader泄漏
- 新生代晋升量逐轮增加:年轻代对象频繁“活过几轮”被送入老年代 → 重点查ThreadLocal未remove、大对象提前分配、缓存膨胀
- Metaspace持续单边增长:不随Full GC回落 → 动态代理(Spring AOP)、Groovy脚本、热更新类未卸载
二、用“生命周期四象限”替代盲目找大对象
别一上来就打开MAT看“Retained Heap Top 10”。先问两个问题:
- 这个数据实际该活多久?(请求级?会话级?天级?)
- 它被谁持有?那个持有者能活多久?(方法局部变量?线程?static字段?类加载器?)
真正危险的是短生命周期数据 → 被长生命周期持有者拽住,比如:一个HTTP请求生成的DTO被塞进static Map,或一次数据库查询结果被ThreadLocal在线程池里跨请求携带。
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
三、高频泄漏点必须烂熟于心
80%以上泄漏集中在以下三处,复习时要能立刻反应出“现象+原因+修复”链条:
- 静态集合无清理:现象是老年代缓慢但稳定上涨;修复不是加synchronized,而是换Caffeine(带LRU+TTL),或至少加定时清理+size限制
-
ThreadLocal未remove:尤其在使用线程池时;修复必须写在finally块里:
try { ... } finally { threadLocal.remove(); } - 资源未关闭:InputStream、Connection、ResultSet等;修复首选try-with-resources,自定义资源类务必实现AutoCloseable
四、动手验证比看十遍文档管用
复习时不光读,要真跑起来:
- 用
jstat -gcutil <pid> 2s</pid>实时观察OU(老年代使用率)是否只升不降 - 模拟泄漏:写个循环往static List里add新对象,用
jmap -dump:live,format=b,file=leak.hprof <pid></pid>抓dump - 用MAT打开,运行Leak Suspects Report,再点开“Dominator Tree”,找Shallow Heap小但Retained Heap巨大的对象
把一次完整排查从监控异常、触发dump、分析引用链到定位代码行走通一遍,印象远超纯理论记忆。










