JVM调优工具、垃圾回收器、OOM排查速览

一、OOM 与内存泄漏核心概念(重点)

1. 内存溢出 OOM(OutOfMemory)

内存空间已经全部占满,没有剩余内存分配新对象,系统无法继续运行,抛出OOM异常。

通俗理解:内存不够用了。

2. 内存泄漏 Memory Leak

程序产生的对象已经业务失效、不会再被使用,但代码存在无效引用,导致GC无法回收,对象常驻堆内存,持续占用内存。

通俗理解:内存被无效对象偷偷占用,释放不掉。

3. 两者关系

内存泄漏日积月累 → 可用内存越来越少 → 最终触发内存溢出OOM。内存泄漏是诱因,OOM是最终结果。

4. 常见内存泄漏场景(生产高频)

  • 静态集合类(static List/Map)无限存放对象,集合全局常驻,对象无法回收

  • ThreadLocal 使用后不 remove,线程复用导致对象长期绑定线程无法释放

  • 未关闭资源:IO流、数据库连接、Redis连接、Socket连接

  • 长生命周期对象持有短生命周期对象引用

  • 匿名内部类、非静态内部类持有外部类引用

  • 循环引用、缓存不设置过期淘汰策略

二、线上 OOM 标准排查思路(高频)

  1. 查看日志:确认OOM类型(堆OOM、元空间OOM、栈OOM、直接内存OOM)

  2. 抓取堆快照:使用 jmap 导出 hprof 文件,分析大对象、常驻对象

  3. 查看线程状态:jstack 排查死锁、死循环、线程阻塞导致对象无法释放

  4. 实时监控GC:jstat 观察 GC 频率、GC耗时、内存变化

  5. 工具分析:MAT/Arthas 定位泄漏对象、引用链、异常代码位置

  6. 定位代码:修复内存泄漏代码、优化对象生命周期、增加资源关闭、缓存过期策略

三、JVM 五大排查工具(jstack/Jmap/Jstat/Jvisualvm/Arthas)

1. Jstack(线程快照工具)

核心作用:生成当前JVM线程快照,排查线程死锁、死循环、CPU飙高、接口卡顿、线程阻塞问题。

常用命令

  • jstack pid:查看线程堆栈信息

  • jstack -l pid > log.txt:导出完整线程日志,包含锁信息

排查场景:CPU100%、线程死锁、请求超时、业务卡死

2. Jmap(堆内存快照工具)

核心作用:查看堆内存配置、对象统计、导出堆快照,专门排查OOM、内存泄漏。

常用命令

  • jmap -heap pid:查看堆内存整体配置与占用

  • jmap -histo pid:查看所有对象数量、占用大小

  • jmap -dump:format=b,file=xxx.hprof pid:导出堆快照文件

注意:dump操作会触发STW,线上尽量低峰期执行

3. Jstat(GC实时监控工具)

核心作用:轻量级实时监控GC状态、内存占用、GC次数、GC耗时,无侵入。

常用命令

  • jstat -gc pid 1000 10:每1秒打印一次GC信息,共10次

排查场景:频繁MinorGC、频繁FullGC、GC耗时过长

4. Jvisualvm(可视化工具)

JDK自带可视化图形工具,集线程监控、堆分析、GC监控、抽样分析于一体,适合本地测试环境分析,线上一般不用。

5. Arthas(阿里线上诊断神器)

核心定位:线上无停机、高性能诊断工具,生产首选。

常用能力

  • thread:查看线程状态、死锁、CPU占比最高线程

  • heapdump:在线导出堆快照

  • gc:实时查看GC统计信息

  • watch:监听方法入参、出参、异常、耗时

优势:轻量、无需重启服务、线上实时定位问题

四、STW、安全点、安全区域

1. STW(Stop the World)

GC执行期间,暂停所有用户业务线程,只保留GC后台线程,保证垃圾回收准确性。

核心结论:所有GC都会产生STW,只是停顿时长不同。

2. 安全点 SafePoint

线程并非随时可以暂停,JVM指定特定位置为安全点(方法返回、循环末尾、异常抛出),只有线程运行到安全点,才可以暂停线程、触发STW,保证数据一致性。

3. 安全区域 SafeRegion

线程处于休眠、阻塞、等待状态,不会修改堆对象数据,整个时间段都是安全区域,无需跑到安全点即可直接暂停线程,避免线程休眠无法响应GC暂停。

五、三色标记、读写屏障、浮动垃圾

1. 三色标记原理

并发GC标记存活对象的核心算法,将堆内对象分为三种状态:

  • 白色:未扫描,默认死亡

  • 灰色:已扫描自身,未扫描引用对象

  • 黑色:自身+引用对象全部扫描完毕,确定存活

2. 漏标问题(并发BUG)

并发标记期间,业务线程修改引用:黑色对象引用白色对象、灰色对象删除白色引用,导致存活对象被标记为死亡,误回收。

3. 读写屏障解决漏标

  • 写屏障:对象引用发生修改时,拦截记录变更,补偿重新标记

  • 读屏障:读取对象引用时拦截,保证标记快照准确,ZGC大量使用

4. 浮动垃圾

并发GC执行过程中,新产生的失效对象,本次GC无法识别回收,只能留到下一次GC清理,这类垃圾称为浮动垃圾。

产生场景:CMS、G1、ZGC等所有并发收集器

特点:无法彻底避免,属于并发GC正常现象