文章背景图

Linux 僵尸进程不断增加:定位父进程、正确回收与代码修复

2026-08-09
1
-
- 分钟

僵尸进程是已经退出、但父进程尚未读取其退出状态的子进程。它几乎不占 CPU 和业务内存,但会保留 PID 和少量进程表信息。数量持续增长时,最终可能耗尽 PID 或暴露父进程的回收逻辑缺陷。

一、确认僵尸进程数量

ps -eo stat | awk '$1 ~ /^Z/ {count++} END {print count+0}'
ps -eo pid,ppid,stat,lstart,cmd | awk '$3 ~ /^Z/'
top -b -n 1 | head -n 5

STAT 中 Z 或进程名后的 <defunct> 表示僵尸。记录 PID、PPID、出现时间和数量增长速度。

二、按父进程聚合

ps -eo ppid=,stat= | awk '$2 ~ /^Z/ {count[$1]++} END {for (p in count) print count[p],p}' | sort -nr

对僵尸最多的父 PID 继续检查:

ps -fp <ppid>
cat /proc/<ppid>/status
cat /proc/<ppid>/limits
ls -l /proc/<ppid>/exe
systemctl status <service> --no-pager

如果父进程属于容器,还要从宿主机和容器内部确认 PID namespace,不能只根据宿主机 PID 判断业务归属。

三、理解为什么 kill 僵尸无效

僵尸进程已经执行完毕,没有可运行代码,因此对它执行 kill -9 <zombie_pid> 通常无法清除。真正需要处理的是父进程没有调用 wait()waitpid() 或等效机制读取子进程状态。

可以向父进程发送 SIGCHLD 作为低风险尝试,但只有父进程实现了正确处理逻辑才会生效:

kill -s SIGCHLD <ppid>

发送前确认父进程和应用行为,不要对未知系统进程批量发送信号。

四、定位父进程为何不回收

检查父进程日志、线程状态和系统调用:

journalctl _PID=<ppid> --since '-30 min' --no-pager
ps -L -p <ppid> -o pid,tid,stat,wchan:32,comm
strace -f -p <ppid> -e trace=wait4,waitid,clone,fork,vfork -tt

strace 会影响进程并产生大量输出,只应短时间使用,关键业务进程要先评估风险。

常见根因包括:

  • 父进程没有注册 SIGCHLD 处理或没有调用 wait 系列函数。

  • 只回收了一个退出子进程,没有循环回收全部子进程。

  • 父进程线程死锁、事件循环阻塞或异常退出路径未执行回收。

  • Shell 脚本后台启动大量任务但没有 wait

  • 容器的 PID 1 不是合格的 init,不能正确回收孤儿进程。

五、应急处理步骤

  1. 先确认当前 PID 使用情况:

cat /proc/sys/kernel/pid_max
ps -e --no-headers | wc -l
  1. 如果数量稳定且 PID 空间充足,优先保留现场并安排应用修复。

  2. 如果持续快速增长,暂停产生子进程的任务或从入口限流。

  3. 对无状态服务做滚动重启,让父进程退出后由 init 接管并回收僵尸。

  4. 单机服务重启前确认依赖、流量、未完成任务和回滚方案。

不要为了消除僵尸直接重启整台服务器。多数情况下,只需受控重启有问题的父进程或容器。

六、代码与容器层修复

  • C/C++ 正确处理 SIGCHLD,并循环调用 waitpid(-1, &status, WNOHANG)

  • Python 管理 subprocess.Popen 后调用 wait()communicate() 或使用上下文管理。

  • Shell 后台任务保存 PID,并使用 wait 获取退出状态。

  • 容器为多进程模型时使用合适的 init,例如启用运行时 init 选项。

  • 为子进程数量、退出速率和回收失败建立指标。

七、长期治理

  • 监控 Z 状态数量、PID 使用率和进程创建失败。

  • 压测子进程高频退出、并发退出和异常退出场景。

  • 应用日志记录子进程 PID、退出码和回收结果。

  • 容器镜像明确 PID 1 的职责,不让普通业务进程承担不完整的 init 行为。

处理僵尸进程的关键不是“杀死它”,而是找到没有履行回收职责的父进程。

原创

Linux 僵尸进程不断增加:定位父进程、正确回收与代码修复

本文链接: Linux 僵尸进程不断增加:定位父进程、正确回收与代码修复

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

评论交流

文章目录