Linux 进程管理与性能排查实战:从 top、strace 到 perf 的完整决策链 原创

温馨提示:
本文最后更新于 2026-10-08,已超过 0 天没有更新。 若文章内的图片失效(无法正常加载),请留言反馈或直接 联系我。

为什么进程排查是运维的底层能力

监控系统告诉你”机器有问题”,但定位到”哪个进程、哪段代码、哪个系统调用”靠的是进程级工具链。CPU 飙高、内存泄漏、负载虚高、进程 D 状态卡死,这四类问题的排查路径完全不同。本文把 ps、top、strace、perf、vmstat 串成一条可复用的决策链路,而不是孤立地背命令参数。

第一步:先判断瓶颈类型,再选工具

不要一上来就敲 top。先用负载与等待队列区分”真忙”和”卡死”:

uptime
# load average: 8.00 7.2 6.5  —— 负载高不等于 CPU 忙
vmstat 1 5
# 看 r(运行队列)、b(不可中断等待)、wa(IO 等待)、us/sy(用户/内核态)
现象组合 瓶颈 首选工具
r 大、us 高、wa 低 CPU 计算密集 top/perf
b 大、wa 高 磁盘 IO 等待 iostat/iotop
sy 高、r 不大 系统调用/上下文切换频繁 strace/perf
load 高但 CPU 空闲 大量 D 状态进程(等 IO/锁) ps + /proc/pid/stack

关键认知:load average 统计的是”正在运行 + 不可中断睡眠”的进程数。NFS 卡死、磁盘 hang 住时,进程全部进入 D 状态,负载能堆到几十,但 CPU 使用率是 0。只看 CPU 会完全误诊。

第二步:ps 与 top 定位到具体进程

ps 适合快照与脚本,top 适合持续观察。几个真正高频的组合:

# CPU 占用排序,看完整命令行
ps -eo pid,ppid,%cpu,%mem,stat,etime,cmd --sort=-%cpu | head -20

# stat 列是精髓:R 运行 / S 睡眠 / D 不可中断 / Z 僵尸 / + 前台 / 多线程 l
ps -eo pid,stat,wchan:30,cmd | awk '$2 ~ /D/'

在 top 里:按 P 按 CPU 排序、M 按内存排序、H 切换线程视图、1 展开每个 CPU 核心。线程视图对定位 Java、Node、worldserver 这类多线程进程至关重要——进程总 CPU 200% 时,必须下钻到是哪条线程在烧。

# 找到高 CPU 的线程 TID 后
top -H -p <pid>
# 把 TID 转成十六进制,再到 jstack / gdb 里对照线程栈
printf '%x\n' <tid>

第三步:strace 看进程在”求内核做什么”

当进程表现异常(卡住、狂打日志、响应慢)但源码不在手上时,strace 直接展示它与内核的边界——每一次系统调用。

# 附着到运行中的进程,统计系统调用耗时
strace -f -p <pid> -c
# -c 汇总:哪类调用次数最多、耗时最长

# 追踪网络与文件相关调用,并打印时间戳
strace -f -p <pid> -tt -e trace=openat,read,write,connect,recvfrom,sendto 2>&1 | head -100

典型用法:进程”假死”时 attach 上去,若反复看到 futex(..., FUTEX_WAIT),说明在等一把用户态锁(死锁或锁竞争);若卡在某个 read() 指向的 fd,用 ls -l /proc/<pid>/fd/<n> 就能查出它到底在等哪个文件或 socket。生产环境慎用:strace 有可观的 ptrace 开销,排查结束立即 detach。

第四步:perf 从进程下钻到函数

strace 只到系统调用层,CPU 真正耗在用户态哪个函数,要用 perf。

# 采样整个系统 30 秒,生成火焰图原料
perf record -F 99 -a -g -- sleep 30
perf script | stackcollapse-perf.pl | flamegraph.pl > cpu.svg

# 只看单个进程,并直接看 top 函数
perf top -p <pid>

火焰图读法:横轴是采样命中比例(不是时间流逝),纵轴是调用栈。一个”宽平台”就是热点函数。相比盲目猜测,perf 用统计采样给出证据,且开销量化可控。权限不足时需要 kernel.perf_event_paranoid 调整或 root。

内存问题:区分 RSS、缓存与泄漏

内存”被占满”在 Linux 上多半是假象——free 的 buff/cache 是可回收的。真正要盯的是进程的常驻物理内存。

# 按实际内存排序,RSS 单位 KB
ps -eo pid,%mem,rss,cmd --sort=-rss | head

# 持续观察某进程 RSS 是否单调增长(泄漏特征)
watch -n 5 'ps -o rss= -p <pid>'

# 更细:按进程看内存分布
cat /proc/<pid>/status | grep -E 'VmRSS|VmSwap|Threads'
pmap -x <pid> | sort -k3 -n | tail

判断泄漏的标准不是”占用高”,而是”流量回落之后 RSS 不回落、且持续单调上升”。若 VmSwap 持续增长,说明物理内存不足触发了换出,这比 OOM 更早出现,应该在此阶段扩容或限流,而不是等 OOM Killer 动手。

一条可复用的排查决策链

1. uptime / vmstat 1  → 判定 CPU / IO / 锁 哪类瓶颈
2. ps --sort + top -H  → 定位到进程与线程
3. strace -c / -e      → 看系统调用与锁等待
4. perf record / top   → 下钻到用户态热点函数
5. /proc/pid/status    → 核对内存与线程数,留存证据

工具的价值不在参数记得多,而在顺序正确:先分型、再定位、后下钻、留证据。每一步都用证据排除一类原因,最终收敛到根因,而不是在 top 界面里凭直觉乱猜。