面灵AI→

Java 线上排查面试题:CPU 飙高怎么定位

时间
2026-09
来源
牛客网

《面试题目》

  1. 介绍一下你怎么排查 CPU 飙高的线上问题的?
  2. 追问:拿到线程堆栈后,你会关注哪些状态的线程,怎么分析?

《参考解析》

  1. 整体思路:CPU 飙高排查的本质是逐层定位——从哪台机器,到哪个进程、哪个线程、哪行代码。先用监控(如 Grafana)确认是哪台机器哪个实例,登录机器;线上一般一机一实例,进程比较自然能确定。接着 top -H -p <pid> 找占 CPU 最高的线程 tid,因为 jstack 的线程名是十六进制,还要 printf '%x\n' <tid> 换算一次。最后 jstack <pid> 抓堆栈并用十六进制 tid 去 grep,就能看到它正在调用的方法。
  2. 为什么要抓三次堆栈:同样表现为高 CPU,根因不同解法完全不同,区分手段就是对比多次堆栈。线程一直卡在同一行不动,说明在某个 while/for 里出不来,是死循环或递归没有出口;都在同一个方法但行号在变,说明不是死循环,而是数据量过大,要判断是不是异常请求打进来了;每次抓到的栈都不一样,说明线程在正常干活,只是并发度高,问题可能不在这一段代码。
  3. 按线程状态判断:jstack 输出里每个线程都带状态,看状态往往比读调用栈更快猜到根因。RUNNABLE 且吃 CPU,一般是死循环或复杂计算,去看它所在的方法,优化算法逻辑或补退出条件;BLOCKED 且一堆线程卡在同一把锁上,多半是锁粒度太粗或存在热点资源,减小锁粒度或换并发容器;WAITING / TIMED_WAITING 可能是队列空转、连接池配置过大或锁等待,调小核心线程数、检查连接池上限、排查上游是否卡住。如果栈里几乎全是 GC task、reference processing 之类,那其实是 GC 在疯狂工作,应该转去查内存和 GC 日志,而不是继续盯业务代码。
  4. 工具取舍:jstack 是 JDK 自带的,线上零依赖、随时可用,是默认选择;如果允许安装 agent,arthas 更省事——thread 直接列出高 CPU 线程,trace 看方法耗时分布,watch 观察入参和返回值。但工具只是手段,两边目标一致:找到有问题的代码。用 arthas 的 trace/watch 有额外开销,线上高峰期要控制范围和时间。
  5. 容易踩的坑:只抓一次堆栈就下结论,很容易把正常并发的线程误判成死循环;反过来,把持续跑同一方法的线程当成”在干活”也会漏掉慢查询或大循环。另外要区分”这台机器 CPU 高”和”这个服务 CPU 高”,前者可能是同机其它进程或宿主机争抢。