在 CentOS(以及其他 Linux 发行版)中,“僵尸进程(Zombie Process)”本质上是已经结束但父进程尚未回收其退出状态的进程。防止僵尸进程,核心思路是:让父进程正确回收子进程,或避免产生无人回收的子进程。
下面从原理到实践系统说明。
exit())wait() / waitpid()Z(zombie)状态,占用 PID 和进程表项⚠️ 僵尸进程不占 CPU、不占内存,但会占用 PID,过多会导致无法创建新进程。
在 C / Shell / Python 等语言中:
signal(SIGCHLD, SIG_IGN); // 忽略 SIGCHLD,内核自动回收
或
while (waitpid(-1, NULL, WNOHANG) > 0);
import signal
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
✅ 适用于自己写的服务程序
signal(SIGCHLD, SIG_IGN)signal(SIGCHLD, SIG_IGN);
⚠️ 不适用于需要获取子进程退出码的场景
常见问题:
init(PID 1)接管✅ 解决:
daemon()CentOS 7/8 使用 systemd:
[Service]
Type=forking
PIDFile=/run/xxx.pid
ExecStart=/usr/bin/xxx
Restart=on-failure
✅ systemd 会:
nohup / setsid 不当的坑nohup ./app &
如果 app 频繁 fork 子进程但不回收,仍会产生僵尸。
✅ 正确方式:
setsid ./app
或
systemctl start app
如果已经出现僵尸:
ps -ef | grep defunct
找到父进程 PID:
kill -9 父进程PID
✅ 父进程死后,僵尸会被 init / systemd 回收
⚠️ 不能 kill 僵尸本身
ps -A -ostat,ppid,pid,cmd | grep Z
或
top
# 看 Tasks: xx total, x zombie
✅ 防止僵尸进程的关键
wait()SIG_IGN SIGCHLD❌ 错误做法
如果你有:
我可以给你针对性的配置示例。