CPU 长期 100%:定位到具体进程与线程
发布时间:2026-03-28 10:30       
更新时间:2026-03-28 19:47
先说结论:整机 CPU 百分比本身没有价值,定位到进程和线程才有价值。按下面的顺序走,十分钟能拿到具体责任者。
第一步:锁定进程
top 里按大写 P 以 CPU 排序,记下最前面的进程 PID 和命令名。业务进程(java、php-fpm、mysqld)和陌生进程要区别对待;top 里按 c 键展开完整命令行,能看出进程属于哪个应用。陌生名字先看真实路径:ls -l /proc/12345/exe,路径不对劲就先按安全事件处理,别急着优化性能。
第二步:看是不是单核打满
mpstat -P ALL 1 里如果只有一颗核 100%、其余空闲,说明是单线程瓶颈,加核也没用,只能优化代码或把任务拆成并行;所有核都高,才轮到扩容的考虑。这一步两分钟能做完,却经常被跳过。
第三步:下钻到线程
执行 top -H -p 12345,还是按 P 排序,看这个进程内部哪几个线程在烧 CPU,记下线程号,用 printf "%x\n" 线程号 转成十六进制备用。需要时间维度的证据,用 pidstat -p 12345 -t 1 5 连续采五秒,每个线程的 %CPU 都有记录,比 top 的一瞥可信,贴工单里也直观。
第四步:看线程在干什么
Java 应用最方便:jstack 12345 | grep -A 30 "nid=0x刚转的十六进制",直接定位到代码行,卡在哪个方法一目了然。C/C++ 程序用 gdb -p 12345 挂上后执行 thread apply all bt 看所有线程的调用栈(线上服务要评估暂停影响)。连这些工具都没有时,cat /proc/12345/task/线程号/stat 也能看到线程状态。
第五步:区分峰值与异常
定位到代码之后判断性质:业务高峰期的正常消耗,走扩容或优化的排期;平峰期同样拉满的,大概率是死循环、频繁 Full GC、正则回溯失控这类问题,按线索修。高峰结束后再复盘一次:同样的代码低峰不卡,是容量不够;任何时段都卡,才是代码问题。临时止血除了重启,还可以 taskset -cp 0,1 12345 把进程绑到部分核上,给它划个笼子,高峰里也能争取排查时间。
收尾提醒:动手修之前留存证据(top 输出、jstack 快照),否则修完也不知道有没有修对。