科技 · 實用指南
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 數量與子程序完成數。
僅当父程序健康、结束子程序被回收、僵尸數量回到有界基线且無關程序未受影响時,才接受修復。
