先看load average和%Cpu(s)再排查:4核机load>4说明排队,wa高表明磁盘等待而非CPU瓶颈,sy>30%提示锁竞争;线程TID需转16进制才能用jstack定位;perf top可查native热点,需root及调参;strace和pidstat仅作辅助验证。

先看负载和利用率,别急着杀进程
Linux 中 CPU 100% 不等于真“满载”,得拆开看两个关键指标:load average 和 %Cpu(s)。用 top 一进来就按 P 排序,但别只盯着第一行的 99.9% —— 先看右上角的 load average: 4.15, 3.80, 3.20:如果机器是 4 核,1 分钟负载 >4 就说明有任务在排队;再看下方 %Cpu(s): 85.5us, 10.2sy, 0.2wa:若 wa(iowait)高,说明 CPU 在干等磁盘,不是计算瓶颈,杀进程没用;若 sy 持续 >30%,大概率是锁竞争或频繁系统调用,不是业务代码问题。
定位到线程 ID 后,必须转 16 进制再查堆栈
找到高 CPU 的 PID(比如 2633)后,用 top -H -p 2633 或 ps -mp 2633 -o THREAD,tid,time | sort -rn 找出最耗时的线程 TID(比如 3626)。这一步很多人直接拿十进制 TID 去 jstack 里搜,结果啥也找不到——因为 JVM 的线程快照里显示的是十六进制小写格式。必须执行:printf "%x\n" 3626 得到 e18,再用 jstack 2633 | grep "e18" -A 30 才能准确定位到对应线程的堆栈。漏掉这步转换,等于白忙活。
perf top -p 是验证“到底在算什么”的最终手段
当 jstack 显示线程在 RUNNABLE 状态但堆栈全是 native 方法(比如 Unsafe.park、pthread_mutex_lock),或者压根没 Java 线程占高 CPU,就得怀疑是不是 JNI、GC、JIT 编译或内核路径在吃资源。这时 perf top -p 2633 能直接看到函数级热点:如果大量时间在 [unknown] 或 libc-2.x.so 里,可能是本地库死循环;如果集中在 jvm.dll 或 libjvm.so 的 GC 相关函数,就得检查堆大小或 GC 参数。注意:perf 需要 root 权限,且某些容器环境默认禁用 perf_event_paranoid,得先 echo -1 > /proc/sys/kernel/perf_event_paranoid。
strace 和 pidstat 是补位工具,别当成主力
strace -p PID 看起来很直观,但它会严重拖慢目标进程(尤其是高频系统调用场景),还可能掩盖真实行为;pidstat -p PID 1 虽然轻量,但只给平均值,抓不住瞬时毛刺。它们适合两种情况:一是 top 显示某个进程 CPU 使用率忽高忽低,用 pidstat 确认是否周期性抖动;二是 top 里进程状态为 D(不可中断睡眠),用 strace 没反应,反而该立刻切去 iostat -x 1 查磁盘延迟。把它们当“辅助望远镜”,不是“主手术刀”。
真正卡住的地方往往不在第一层表象:比如 wa 高却误判为 CPU 问题,比如线程 ID 没转 16 进制导致堆栈对不上,比如在容器里跑 perf 却忘了调内核参数。排查顺序不是线性的,而是靠指标互验来回收窄——CPU 利用率、负载、iowait、上下文切换数,四个数字对上了,根因才不会跑偏。







