核心是快速定位泄漏源头,而非加内存;需提前配置JVM参数留证据,通过GC日志看老年代持续增长与Full GC频增趋势,再用jstat/jmap锁住异常对象,最后用MAT分析堆转储,沿GC Roots定位静态集合、ThreadLocal等强引用路径。

生产环境 Spring Boot 出现内存溢出或 GC 异常,核心不是“加内存”,而是快速定位泄漏源头。关键在三件事:留证据、看趋势、锁对象。
一、提前配置 JVM 参数,让问题可追溯
上线前必须加上这些参数,否则故障时无从下手:
- 生成堆转储:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dumps/
- 记录详细 GC 日志:-Xloggc:/data/logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xlog:gc*:filecount=5,filesize=10M
- 启用 JMX(方便实时监控):-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999
注意:路径需确保应用有写权限;日志文件按大小和数量轮转,避免占满磁盘。
二、通过 GC 日志识别泄漏迹象
打开 gc.log,重点看三点:
- 老年代使用率是否持续上升:比如 OU(Old Used)从 30% → 60% → 90%,且每次 Full GC 后下降极少(如只降 2%~5%)
- Full GC 频率是否陡增:从几小时一次变成几分钟一次,甚至每秒多次
- GC 后堆总占用是否不降反升:例如 GC 前总堆 1.8G,GC 后仍为 1.75G,反复如此
出现任一现象,基本可判定存在内存泄漏——对象被强引用持有,GC 无法回收。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
三、用 jstat 和 jmap 快速现场诊断
服务还在运行但内存告警时,立即执行:
- jstat -gc -h10 <pid> 2000:每 2 秒输出一次 GC 统计,观察 OU、OGC(老年代容量)、FGC(Full GC 次数)是否单向增长
- jmap -histo:live <pid> | head -20:列出堆中存活对象 Top 20,重点关注自定义类(如 com.xxx.cache.XxxMap)、集合类(HashMap、ArrayList)、String、byte[] 占比异常高
- jmap -dump:format=b,file=/data/dumps/heap.hprof <pid>:手动触发堆快照(建议先停流量或选低峰期)
如果发现某个 Map 实例数量达数万、或某 Controller 类实例持续不释放,就是突破口。
四、用 MAT 分析堆转储,定位泄漏根因
将 .hprof 文件用 Eclipse MAT 打开后,按顺序操作:
- 点开 Leak Suspects Report,MAT 会自动标出最可疑的泄漏链(通常含“dominator tree”提示)
- 查看 Dominator Tree,按 “Retained Heap” 排序,找自己项目的类(非 JDK 类)排在前列的
- 右键该对象 → Path to GC Roots → 勾选 “exclude weak/soft references”,看谁在强引用它
常见泄漏路径包括:静态集合未清理、ThreadLocal 没 remove()、监听器注册后未注销、缓存未设过期或淘汰策略。

















