系统突然出现 CPU 飙高,你如何排查?
场景二:如果系统突然出现 CPU 飙高,你如何排查?
CPU 飙高是线上非常紧急的故障。排查思路需要分两步走:先通过 Linux 命令定位是哪个进程、哪个线程出了问题,再结合 JVM 工具分析具体的代码原因。
第一步:Linux 系统层面的快速定位
- 确认负载情况:使用
top命令查看系统整体负载(load average)和 CPU 使用率。按P键让进程按 CPU 占用率降序排列,迅速找到占用 CPU 最高的 Java 进程 PID。 - 定位具体线程:执行
top -Hp <PID>,查看该 Java 进程下所有线程的 CPU 占用情况,找到占用 CPU 最高的线程 ID(TID)。 - 转换线程 ID:将找到的线程 ID(十进制)转换为十六进制,命令为
printf "%x\n" <TID>。因为后续 JVM 堆栈中显示的线程 ID 是十六进制的。
第二步:JVM 应用层面的深度分析
- 导出线程堆栈:使用
jstack <PID> | grep <十六进制TID> -A 20命令,打印出该高负载线程的堆栈信息。 - 分析堆栈信息(核心):
- 业务代码死循环/复杂计算:如果堆栈指向了你自己的业务代码(如某个
while循环、复杂的正则匹配、JSON 序列化等),说明是代码逻辑导致了 CPU 飙升。 - 频繁 Full GC:如果堆栈中大量出现
VM Thread或GC task thread,且 CPU 飙高,通常意味着系统内存不足,JVM 在疯狂进行 Full GC(即“GC 抖动”)。此时需要配合jstat -gcutil <PID> 1000观察 GC 频率,并使用jmap或 MAT 工具分析堆内存快照,排查是否存在内存泄漏或大对象分配。 - 锁竞争激烈:如果堆栈显示大量线程处于
BLOCKED状态,或者都在等待同一把锁,说明存在严重的锁竞争,导致 CPU 消耗在上下文切换上。
- 业务代码死循环/复杂计算:如果堆栈指向了你自己的业务代码(如某个
总结排查口诀:top找进程 ->top -Hp找线程 ->printf转十六进制 ->jstack抓堆栈 -> 分析代码逻辑或 GC 状况。
