← 返回现象因果
☕ 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)→ 这是关键特征!
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层 · 全栈资料库