这个场景解决什么
ps 里出现一批状态为 Z 的进程,说明它们已经结束,只等父进程调用 wait 回收进程表项。僵尸本身几乎没有内存占用,也没有地址空间可以投递信号,所以处理方向从来不是对付僵尸,而是找到并修复它的父进程:要么补齐回收逻辑,要么重启父进程。少量短命僵尸无害,持续堆积才说明父进程有缺陷。
基本信息
| 场景 | 僵尸进程持续堆积 |
|---|---|
| 判据 | ps 的 stat 列出现 Z 或 Z+ |
| 处理方向 | 修复父进程的回收逻辑,或重启父进程 |
| 组合命令 | ps 过滤 Z 状态 + 按 ppid 统计来源 |
典型使用场景
- 巡检发现大量 Z 状态进程,先统计由哪个父进程产生
- 自研脚本漏写 wait 导致僵尸堆积,定位后补上回收逻辑
- 老服务在高并发下漏回收子进程,考虑升级或重启
- 进程数告警时排除僵尸造成的计数虚高
- 容器内 PID 1 不回收退出进程导致整体异常
- 压测前后对比僵尸数量,判断代码是否存在回收缺陷
定位与处理
定位与处理
ps -eo stat,pid,ppid,cmd | awk '$1 ~ /^Z/' | head # 列出僵尸进程
ps -eo stat,pid,ppid,cmd | awk '$1 ~ /^Z/{print $3}' | sort | uniq -c | sort -rn # 谁制造了僵尸
ps -o pid,stat,cmd -p <父PID> # 父进程是否还在
pstree -p <父PID> # 看它的子进程结构
ps -eo stat | grep -c Z # 统计当前僵尸总数
systemctl restart <相关服务> # 应急:重启父进程清空僵尸进程状态与处理
| 状态 | 含义 | 处理方向 |
|---|---|---|
| Z | 已结束,等待父进程回收 | 修父进程回收逻辑或重启父进程 |
| Z+ | 前台进程的僵尸子进程 | 同样只能由父进程处理 |
| 父进程存活 | 僵尸会一直留着 | 修代码或重启父进程,注意会带走其子进程 |
| 父进程已消失 | 由 init 接管并回收 | 通常会自动清理,无需干预 |
僵尸进程只占进程表项,几乎不消耗内存与 CPU。少量短命僵尸是正常现象,持续堆积才说明父进程没有正确回收,不必看到 Z 就紧张。
kill 僵尸永远无效:它已经退出,也没有可投递信号的地址空间,只会得到 No such process。不要在僵尸本身身上耗费时间。
容器里由 PID 1 负责回收子进程:如果入口脚本没写回收逻辑,长期运行会积累僵尸,改用带回收能力的 init(如 tini)是常见做法。