← 全部笔记

Linux 上排查 CPU 占用高的五个步骤

2026-10-12 系统与运维 约 7 分钟

以前遇到 CPU 高就是 top 看一眼,看到某个进程 300% 就重启了事。 后来才明白,重启只是把问题推迟。真正该先搞清楚的是:这个 CPU 是在干活,还是在等东西。

第一步:先看全局,别急着看进程

top

只看顶部那几行就够,重点在 %Cpu(s) 这一行:

  • us 高 —— 用户态在算,通常是自己代码的问题
  • sy 高 —— 内核态,看系统调用、上下文切换、网络收发
  • wa 高 —— 在等磁盘,这不是 CPU 忙,是 IO 慢
  • si / hi 高 —— 软硬中断,常见于网卡压力大
  • st 高 —— 被宿主机其他虚拟机抢了,云主机上很常见

如果 wa 高而 us 不高,去查磁盘和内存,别去翻代码。这一步判断错,后面全白做。

第二步:定位到进程

top -o %CPU
# 或按内存排序,有时是 GC 引起的高 CPU
top -o %MEM

记下 PID。同时留意 RES(常驻内存)——如果内存也一直涨,多半是内存压力导致频繁回收,CPU 高只是结果。

第三步:定位到线程

多线程程序里,进程总共 300% 不代表某个线程有问题。

top -H -p <PID>
# 或者
ps -T -p <PID> -o spid,pcpu,comm --sort=-pcpu | head

Java 程序可以把线程 ID 转十六进制,去 jstack 输出里找 nid=0x... 对应的栈; C/C++ 程序直接用 gdb -p <PID> 加 thread apply all bt。

第四步:看它到底在调什么

有 perf 就用 perf,没有就先装:

# 采样 10 秒,看热函数
perf top -p <PID>

# 或者抓一段时间的调用栈
perf record -F 99 -p <PID> -g -- sleep 15
perf report

没有 perf 权限时,用 pidstat 看上下文切换也很有效:

pidstat -w -t -p <PID> 1 5

cswch/s(自愿切换)很高,说明在等锁或等 IO; nvcswch/s(非自愿)很高,说明时间片被抢,通常是线程开太多。

第五步:对着现象下结论

把前面几步的结果对上号,基本就定方向了:

现象 大概率原因
us 高,单个线程 100% 死循环、正则回溯、大对象序列化
sy 高,cswch/s 高 锁竞争、线程过多、频繁小包读写
wa 高 慢盘、swap 抖动、大文件顺序读
st 高 宿主机超卖,只能换机器或错峰

两个我踩过的坑

坑一:只看平均负载

uptime 里的 load average 包含不可中断睡眠的进程,所以磁盘卡住时 load 会飙升, 但 CPU 可能很闲。拿 load 当 CPU 指标会误判。

坑二:忘了看容器限制

在容器里 top 看到的是宿主机的 CPU 数和总占用,容易以为还有余量。 先确认自己的配额:

cat /sys/fs/cgroup/cpu.max         # cgroup v2
cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us   # cgroup v1

配额打满时进程会被 throttle,表现是「明明有 8 核但跑不快」,这时候再优化代码意义不大。


顺序不能跳:全局 → 进程 → 线程 → 系统调用 → 结论。 跳过任何一步,都会得到「CPU 很高,不知道为啥」这种结论。