Linux 进程管理实战:用 ps、top、strace 定位 CPU 占用与僵尸进程

一、ps:静态查看进程快照

ps 是最基础的进程查看命令,它显示的是执行瞬间的进程状态快照,适合快速浏览和脚本处理。最常用的组合是 ps aux,其中 a 表示显示所有用户的进程,u 表示以用户为主的格式输出,x 表示显示没有控制终端的进程。如果只想看某个程序的进程,可以用 ps aux | grep 关键词,或者用 pgrep -l 关键词 直接列出匹配的进程号和命令。

执行 ps aux 后,每一行代表一个进程,关键的列有 USER(运行用户)、PID(进程号)、%CPU(CPU 占用百分比)、%MEM(内存占用百分比)、VSZ 与 RSS(虚拟内存与常驻内存)、STAT(进程状态)、START(启动时间)和 COMMAND(命令)。RSS 常驻内存是判断进程实际占用内存的重要依据,VSZ 虚拟内存往往虚高,参考意义不大。

STAT 状态列是排查问题的重点。R 表示正在运行或可运行,S 表示可中断睡眠,D 表示不可中断睡眠(通常是在等待磁盘 IO),Z 表示僵尸进程,T 表示已停止,I 表示空闲的内核线程。如果看到大量 D 状态进程,说明磁盘 IO 可能是瓶颈;如果看到 Z 状态,说明有僵尸进程需要处理。状态列后面有时会跟附加字符,比如 s 表示会话首进程,l 表示多线程进程,+ 表示前台进程组。

想按 CPU 或内存排序查看,可以用 ps aux --sort=-%cpu 和 ps aux --sort=-%mem,倒序排列后排在最前面的就是占用最高的进程。配合 head 命令可以只看前十个,比如 ps aux --sort=-%cpu | head -n 11。脚本处理时可以用 ps -o 自定义输出字段,例如 ps -eo pid,user,%cpu,%mem,cmd --sort=-%cpu | head -n 10,这样输出的格式完全可控。

二、top 与 htop:实时监控进程

ps 是静态快照,要看动态变化就得用 top。top 默认每三秒刷新一次,第一行显示系统运行时间和负载均值,第二行是进程总数与运行、睡眠、僵尸进程数量,第三行是 CPU 使用率(us 用户态、sy 内核态、wa 等待 IO、id 空闲、st 被虚拟机偷走的时间),第四五行是内存与交换分区使用情况。负载均值代表过去 1 分钟、5 分钟、15 分钟的平均活跃进程数,一般以 CPU 核心数为参考线。

top 运行中可以按快捷键切换排序:P 按 CPU 排序,M 按内存排序,T 按运行时间排序,k 可以杀掉指定进程,r 可以调整进程优先级(renice)。按数字 1 可以查看每个 CPU 核心的使用情况,对于多核服务器判断是否单核跑满很有用。按大写 W 可以把当前设置保存为配置文件,下次启动自动生效。按 H 可以切换线程视图,查看多线程进程内部每个线程的占用,Java、PHP-FPM 这类多线程进程排查时很常用。

htop 是 top 的增强版,彩色显示、支持鼠标操作和树形视图,按 F5 可以查看进程树,按 F6 选择排序字段,按 F9 杀进程。Debian 和 Ubuntu 上 apt install htop 即可安装,CentOS 用 yum install htop。htop 的树形视图对理解进程间的父子关系帮助很大,比如定位是哪个父进程派生出一堆子进程吃满资源。

三、僵尸进程:成因与处理

僵尸进程是 Linux 新手最容易困惑的概念。进程退出时并不会立刻消失,而是先变成僵尸状态(STAT 为 Z),等待父进程调用 wait 系统调用读取它的退出状态。如果父进程没有及时处理,僵尸进程就会一直留在进程表里。僵尸进程是进程生命周期中的正常中间状态,短暂出现没有问题,长期堆积才是故障。

僵尸进程不占用 CPU 和内存,但它会占用 PID 和进程表项,如果大量堆积,可能导致系统无法创建新进程。查找僵尸进程用 ps aux | awk '$8=="Z"',或者看 top 第二行的 zombies 计数。结合父子关系可以进一步定位:ps -o pid,ppid,stat,cmd 查看僵尸进程的 PPID,找到它的父进程。

处理僵尸进程的思路是处理它的父进程:僵尸进程无法被 kill -9 杀掉,因为它已经死了。如果父进程还在,可以 kill 父进程,让 init 或 systemd 收养并清理僵尸;如果父进程是长期运行的守护进程,需要修复程序让它正确处理 SIGCHLD 信号,或者重启该服务。预防措施是在程序里注册 SIGCHLD 信号处理函数,或使用 systemd 的服务管理机制。常见的产生源是后台脚本 fork 子进程后没有 wait,排查时优先检查定时任务和常驻脚本。

四、strace:追踪进程的系统调用

当进程 CPU 占用不高但响应很慢时,问题往往出在系统调用上,这时候 strace 是利器。strace -p PID 可以附加到运行中的进程,实时打印它发起的系统调用。比如进程卡在读取文件上,你会看到大量 read 调用没有返回;卡在网络请求上,会看到 connect 或 recvfrom 挂起;卡在锁上,会看到 fcntl 或 flock 反复出现。

strace -c -p PID 可以统计一段时间内各类系统调用的次数和耗时,结束时按 Ctrl+C 输出汇总表,一眼就能看出瓶颈在哪一类调用上。strace -e trace=network -p PID 只跟踪网络相关调用,排查网络问题更聚焦;-e trace=file 只跟踪文件相关调用。strace 需要 root 权限,附加到别的用户进程时尤其如此。注意 strace 会让目标进程明显变慢,生产环境要谨慎使用,排查完立即断开。

一个典型场景:网站偶发卡顿,用 strace 发现 PHP-FPM 进程大量时间花在 stat 和 open 系统调用上,进一步定位到磁盘 IO 慢或者文件系统缓存失效,问题就水落石出了。另一个场景:进程一直不退出,strace 看到它在循环尝试 connect 一个不通的地址,配合 ss 或 tcpdump 就能确认是外部依赖服务挂了。

五、进程优先级与信号

进程优先级用 nice 值表示,范围是 -20 到 19,数值越小优先级越高。普通用户只能调高 nice 值(降低优先级),root 可以调低。启动时用 nice -n 10 command 设置,运行中调整用 renice -n 10 -p PID。当备份、压缩这类耗时任务和线上服务抢 CPU 时,给它们调高 nice 值(比如 10 到 15),让网站进程优先获得 CPU,是成本最低的调度优化。

信号是进程间通信的基本方式。kill -l 可以查看全部信号,最常用的是 SIGTERM(15,礼貌终止,进程可以清理后退出)和 SIGKILL(9,强制杀死,进程没有机会清理)。排查问题时优先用 15 号信号,只有进程无响应才用 9 号。kill -HUP PID 常用于让守护进程重新加载配置,Nginx 和 php-fpm 都支持这种方式,比重启服务更平滑,不会中断正在处理的请求。

六、systemd 下的进程管理

现代 Linux 发行版都用 systemd 管理服务。systemctl status 服务名 可以看到服务进程的状态、主 PID 和最近的日志;systemctl list-units --type=service 列出所有服务。systemd 把进程组织进 cgroup,用 systemd-cgls 可以查看进程树,systemd-cgtop 可以按 cgroup 查看资源占用,比 top 更直观地看出哪个服务在吃资源。配合 journalctl -u 服务名 -f 可以实时跟踪服务日志,排查进程异常退出时先看这里。

对于站点排查,把 ps、top、strace 和 systemd 工具组合起来:先 ps aux --sort=-%cpu 找嫌疑进程,再用 top 确认变化趋势,用 strace 深挖系统调用,最后定位到具体服务用 systemctl 处理。如果进程反复崩溃,检查 systemd 的 Restart 策略和 OOM 记录,dmesg 或 journalctl 里会有内核杀进程的痕迹。这套流程基本能覆盖日常九成的进程问题。

总结

进程管理没有捷径,靠的是对命令的熟练掌握和清晰的排查思路。建议在测试服务器上反复练习这些命令,熟悉每个状态和字段的含义。先把 ps 和 top 用熟,再逐步掌握 strace 和 systemd 工具,遇到问题按先看后查再处理的顺序推进。下次网站再出现 CPU 飙升,你就能从容地定位问题并解决它了。

Last modification:August 23rd, 2026 at 08:08 am

Leave a Comment