在 CentOS(以及其他 Linux 发行版)中出现僵尸进程(zombie process),本质上不是系统 bug,而是 进程生命周期 + 父进程回收机制 导致的一种正常现象。下面从原因、原理和解决方向来说明。
僵尸进程是:
已经结束运行,但还没有被父进程回收的进程
它已经:
Z(Zombie)ps 中能看到wait() / waitpid()这是最主要原因。
在 Linux 中:
SIGCHLDwait() / waitpid() 来:
如果父进程:
SIGCHLDwait()➡ 子进程就成为僵尸进程
常见代码问题包括:
fork(),不 wait()SIGCHLD 但没正确处理示例(错误):
pid_t pid = fork();
if (pid == 0) {
exit(0);
}
// 父进程没有 wait()
while (1) {
sleep(1);
}
常见于:
例如:
& 后台执行子进程如果:
那么:
wait(),僵尸通常会被回收⚠️ 但如果 init 本身有问题(如 Docker 容器没有正确 init),僵尸可能长期存在。
ps -eo pid,ppid,stat,cmd | grep 'Z'
或:
top
# 看 Tasks: xxx zombie
示例输出:
PID PPID STAT CMD
1234 1000 Z [sh] <defunct>
✅ 不会占用 CPU
✅ 不会占用内存
❌ 但会:
因为:
僵尸进程已经死了,只是还没注销
kill -9 是无效的。
✅ 正确做法是:
wait() / waitpid()SIGCHLD 信号示例:
signal(SIGCHLD, SIG_IGN); // 简单粗暴(不推荐生产)
或:
while (waitpid(-1, NULL, WNOHANG) > 0);
ps -ef | grep 僵尸PID
找到父进程(PPID),然后:
kill -HUP 父进程PID
# 或
systemctl restart 服务名
父进程重启后,通常会回收子进程。
错误写法:
some_command &
改进:
some_command &
wait
或在脚本开头:
trap '' SIGCHLD
Docker 中:
tini 或 --initdocker run --init ...
CentOS 本身 不会主动产生僵尸进程,但:
systemd✅ 并非 CentOS 问题,而是 用户态程序问题
CentOS 出现僵尸进程,是因为子进程退出后,父进程没有回收它。
如果你愿意,可以把:
ps -ef贴出来,我可以帮你精确定位是哪一段代码或配置导致的。