jvm之常见线上问题排查
一、OOM 排查 完整流程
1. 前置配置(线上必开)
1 | |
OOM 自动生成堆快照,避免现场丢失。
2. 排查步骤
- 拿到进程 PID
- 若未自动 dump,手动导出:
1 | |
- 使用 MAT / VisualVM 打开堆文件
- 核心分析点:
- 大对象、超大集合
- 实例数量异常多的类
- 支配树:查看谁持有引用无法释放
- 线程栈:定位业务代码位置
3. 常见 OOM 类型
- Java heap space:堆内存不足、内存泄漏
- Metaspace:元空间溢出(动态类、CGLIB、反射)
- Direct Buffer:堆外内存溢出(NIO 未释放)
二、内存泄漏 8 大经典场景
静态集合类
static List/Map全局常驻,对象放入后永不回收。单例模式
单例长期持有业务对象引用。
资源连接未关闭
Connection、Statement、ResultSet、IO 流、Socket 只创建不 close。
长生命周期持有短生命周期对象
比如缓存、全局上下文持有临时对象。
内部类 / 匿名内部类
隐式持有外部类引用,导致外部类无法回收。
缓存无淘汰策略
LocalCache、Guava Cache 不设过期、不限制容量。
ThreadLocal 未 remove
线程复用(线程池)导致弱引用 key 回收,value 强引用泄漏。
非手动堆外内存
ByteBuffer 直接内存、Netty 缓冲区未释放。
核心本质:无用对象被强引用持续持有,GC 无法回收
三、死锁排查 流程 + 原理
1. 死锁必要四大条件
- 互斥条件
- 请求与保持
- 不可剥夺
- 循环等待
2. 排查步骤
- 执行
1 | |
- 搜索关键字:
Found one Java-level deadlock - 直接输出:
- 互相等待的两个线程
- 各自持有的锁、等待的锁
- 精确到类名 + 行号
3. 解决
- 统一锁顺序
- 尝试限时锁
tryLock(time) - 缩小锁粒度
四、CPU 过高 排查完整步骤(面试高频)
1. 定位高 CPU 线程
- 查看进程 CPU
1 | |
- 查看该进程下所有线程 CPU 占用
1 | |
- 记录 CPU 最高的线程 ID,转为 16 进制
1 | |
2. 定位代码行
1 | |
- 直接打印出耗 CPU 方法、堆栈、代码行号
3. 高频导致 CPU 飙高的代码
- 死循环 while (true) 无休眠
- 频繁正则、递归过深
- 大量序列化 / 反序列化
- 无限自旋 CAS、空轮询
- 频繁 Full GC(GC 线程占满 CPU)
五、快速总结
OOM
开启 OOM 自动 dump → jmap 导出 → MAT 分析大对象 / 引用链 → 定位泄漏代码。
内存泄漏
静态集合、单例、连接未关闭、ThreadLocal、缓存不淘汰、内部类、堆外内存、长生命周期引用。
死锁
jstack 检索 deadlock,查看互相等待锁 + 代码行;解决:统一锁顺序、限时锁。
CPU 过高
top 定位进程 → top -H 找高 CPU 线程 → 转 16 进制 → jstack 定位具体卡死 / 循环代码。
jvm之常见线上问题排查
http://hanqichuan.com/2026/04/17/jvm/JVM之常见线上问题排查/