← 返回现象因果

☕ JVM 层的因与果

Full GC 频繁 / OOM / 死锁 —— JVM 内部的问题会引发什么现象

🧹Full GC 频繁CPU偏高+卡顿
原因:老年代不够用(大对象直接进老年代 / Survivor 太小 / 泄漏回收不掉)。
因果流程图
老年代不够用 Full GC 拼命跑 STW 停顿应用 CPU偏高接口卡+超时
1
CPU 偏高(GC 线程占用)→ 但不是单线程 100%,是整体偏高(和死循环的区别!)
2
接口周期性卡顿 (每次 Full GC 时 STW) → RT 抖动,时好时坏
3
健康检查超时 → 可能被注册中心摘除 → 服务下线
4
排查:jstat -gcutil PID 看 FGC 次数 → 找为什么老年代满
# jstat 看 GC 情况(每秒刷新) jstat -gcutil <PID> 1000 # 输出: # S0 S1 E O M YGC YGCT FGC FGCT # 0.00 85.2 73.1 98.5 95.3 142 3.2 38 12.5 # ↑FGC=38 很高! O=98.5% 老年代快满了!
和死循环的区别:Full GC 导致的 CPU 高是整体偏高(所有 GC 线程都在跑);死循环是单线程 100%。看 top -H 就能区分。
💥OOM 内存溢出服务挂
原因:堆装不下了 + GC 也回收不出足够空间,只能放弃。
因果流程图
堆满+GC救不回 OutOfMemoryError 进程退出 服务挂
1
服务直接挂 (进程退出,要重启) → 可能触发 K8s 自动重启
2
OOM 前先频繁 Full GC → 所以 OOM 前往往先经历 CPU 高 + 卡顿
3
看具体报错:heap space(堆) / Metaspace(类太多) / Direct memory(NIO) / unable to create thread(线程数)
# 必须配的 JVM 参数(防 OOM 时没现场) -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dump/ # OOM 时自动 dump 堆快照,不用等出事再手动 dump(手动 dump 会 STW)
🔒死锁(互相等锁)CPU不高但全卡
原因:两个线程互相等对方持有的锁,谁都不放手,全部卡住。
因果流程图
A等B的锁 + B等A的锁 全部卡住 CPU不高但请求全超时
1
CPU 不高(线程都在 WAITING/BLOCKED,不消耗 CPU)→ 这是关键特征!
2
请求全超时 (线程被锁住,新请求也没线程处理)
3
线程数飙升(线程池创建新线程尝试处理,但都被锁住)
4
排查:jstack 搜 "Found one Java-level deadlock" → 自动检测
# jstack 自动检测死锁 jstack <PID> | grep -A 20 "deadlock" # 输出: # Found one Java-level deadlock: # "Thread-1" waiting to lock 0x... held by "Thread-2" # "Thread-2" waiting to lock 0x... held by "Thread-1"
和死循环正相反:死循环是"忙死"(CPU 满但不死);死锁是"等死"(CPU 不高但全卡住)。看 CPU 高低就能区分。
JVM层因果总结:FullGC→CPU偏高+周期卡顿;OOM→直接挂;死锁→CPU不高但全卡。三种问题的现象完全不同,排查方法也不同。
现象因果 · JVM层 · 全栈资料库