科技 · 实用指南
Linux 出现 defunct 僵尸进程?动手前先证明父进程与 wait 边界
僵尸进程已经结束;真正负责清理的是仍存活的父进程、subreaper 或容器 PID 1。先绑定子进程与父进程身份,再只修复一个安全的回收边界。

僵尸进程不是还能再次被终止的运行任务,而是已结束子进程留下的状态记录,等待父进程或回收者读取。因此安全排查应从父进程身份开始,而不是从更强信号开始。
固定子进程 PID 与启动时间、父进程 PID 与启动时间、服务或容器边界以及 Z 状态数量趋势。然后只修复真正负责 wait 的进程,并通过原启动路径证明回收数量受控。
1. 重启父进程前先冻结记录
保存完整 ps 输出、子 PID、父 PID、命令名、用户、容器或 unit、首次观察时间和 Z 状态数量。只要路径仍存在,就读取 /proc/CHILD/stat 与 /proc/PARENT/stat,并保存各自启动时间。
不要先对 CHILD 执行 kill -9,也不要批量终止所有父进程。子进程已经结束,批量命令却可能中断无关服务。
2. 证明仍存活的父进程与 wait 边界
在同一命名空间视图确认状态 Z 与 PPID,再把父进程映射到可执行文件、启动时间、服务、supervisor 与部署。僵尸记录存在,是因为负责的父进程或 subreaper 尚未调用 wait 系列。
检查父进程是否健康、卡住、过载、配置错误,或只是处于短暂回收间隔。稳定或上升的数量才支持持续缺陷判断。
3. 纳入 PID 命名空间与 subreaper
容器中的 PID 1 可能是应用或小型 init,并不等于宿主机 init。记录容器内进程树与宿主侧容器身份;Docker 文档说明 --init 可提供负责回收的 init。
不要假定添加 init 就能修复应用代码。它能回收被收养的后代,但长期父进程仍必须正确回收自己的子进程。
4. 选择对父进程影响最小的修复
如果程序由你维护,应修复完整子进程生命周期:回收每个已结束子进程,处理突发和错误路径,并用相同并发与失败时序测试。
第三方软件优先使用有文档的服务重启或升级。只有在明确依赖、回滚与重启路径后,才考虑结束父进程。
5. 通过原启动器验证有界回收
用相同 systemd unit、容器命令、supervisor 或 shell wrapper 运行原工作负载,按固定间隔采样父进程身份、Z 数量与子进程完成数。
仅当父进程健康、结束子进程被回收、僵尸数量回到有界基线且无关进程未受影响时,才接受修复。
