Skip to content

P03 线上突发 CPU 飙高怎么定位和解决 ​

面试题:线上接口突然卡死,服务器 CPU 直接飙到 100%+,如何快速定位到是哪一行代码导致的?

核心答案:三命令定位法 ​

第 1 步:top 找到"罪魁祸首"进程 ​

执行 top,按 CPU 占用排序,找到 CPU 消耗最高的 Java 进程的 PID。

示例:进程 18720 的 CPU 占用达到 195%(说明它占用了接近两个核),基本可以确定就是它在搞事情。

第 2 步:top -H 找到进程内最耗 CPU 的线程 ​

bash
top -H -p <PID>

-H 表示按线程(Thread)维度展示,-p 指定进程。此时能看到该进程内 CPU 占用最高的几个线程 ID(十进制)。

然后把这个线程 ID 转成 16 进制:

bash
printf "%x\n" <线程ID>

因为 jstack 输出里的线程号 nid 是十六进制的,需要对齐才能匹配。

第 3 步:jstack 过滤该线程的调用栈,定位到具体代码 ​

bash
jstack <进程PID> | grep <16进制线程ID> -A 20

-A 20 表示显示匹配行及其后 20 行。输出里的调用栈顶部就是该线程正在执行的代码,一路往下就能定位到具体类、方法、行号。

示例:最终定位到 UserController.getUser() 方法的第 19 行,打开代码一看,原来这里写了一个死循环——CPU 飙高的根源。

加分点 ​

  • top 默认展示进程;top -H 展示线程(线程号即 LWP/轻量级进程号)。
  • 线程 ID 转十六进制也可以用 printf "%x\n" <tid>,这是面试官常追问的细节。
  • 如果 CPU 飙到 N × 100%,说明有 N 个线程在忙,往往不是单点问题。
  • CPU 飙高的常见原因不止死循环:频繁 Full GC、正则回溯灾难、JSON 大对象序列化、自旋等待等。若怀疑 GC,可再用 jstat -gcutil <pid> 1000 观察 GC 频率。
  • 配合 jstack 多打几次,如果某线程一直卡在同一位置,基本就是问题线程。

一句话总结 ​

top 找进程 → top -H -p <pid> 找线程 → 线程号转十六进制 → jstack <pid> | grep -A 20 <十六进制tid> 定位到具体代码行。

基于 VitePress 重建