在 CentOS(以及其他 Linux 发行版)中,僵尸进程(Zombie Process)本质上是“已经终止、但父进程尚未回收其退出状态”的进程。预防僵尸进程,重点在于父进程正确处理子进程退出,或避免不合理的进程模型。
下面从原理到实践系统说明。
exit())wait() / waitpid()Z 状态(僵尸)僵尸进程不占 CPU、不占内存,但占用 PID,过多会导致无法创建新进程。
wait() / waitpid()pid_t pid = fork();
if (pid == 0) {
// 子进程
exit(0);
} else {
wait(NULL); // 回收子进程
}
waitpid(..., WNOHANG)while (waitpid(-1, NULL, WNOHANG) > 0);
SIGCHLD 异步回收(服务器常用)#include <signal.h>
#include <sys/wait.h>
void sigchld_handler(int sig) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
signal(SIGCHLD, sigchld_handler);
✅ 优点:
fork() + setsid() 双层 fork(守护进程经典做法)父进程
└── 子进程(fork一次)
└── 孙进程(fork二次,真正干活)
init(PID 1)接管init 会自动回收✅ 常用于:
init / systemd 接管子进程(推荐现代方案)在 CentOS 7+:
systemd-run --scope --unit=mytask ./myprogram
或写成 systemd service
✅ systemd 会自动回收子进程
SIGCHLD(不推荐但可行)signal(SIGCHLD, SIG_IGN);
⚠ 风险:
nohup xxx & 不规范写法# 不推荐
nohup ./app &
# 推荐
systemctl start yourapp
supervisor / systemd 管理进程ps -eo stat,pid,ppid,cmd | grep '^Z'
或
top
# 看 Tasks: zombie
ps -eo ppid,stat,cmd | awk '$2=="Z"'
找出其父进程并修复代码或重启服务。
❌ 不能 kill -9
✅ 只能:
init 接管后自动消失| 场景 | 推荐方式 |
|---|---|
| 自己写 C / Python | waitpid + SIGCHLD |
| 守护进程 | 双 fork |
| 服务运行 | systemd |
| 运维管理 | supervisor |
| 临时任务 | systemd-run |
如果你愿意,我可以:
直接说场景即可。