僵尸进程(Zombie Process)在 Ubuntu(以及所有 Linux 系统)中,本质上是子进程已经结束,但父进程还没有回收它的退出状态而产生的一种“已死但未彻底消失”的进程。
下面从产生原因、原理、示例、查看和避免方法几个方面说明。
僵尸进程产生的必要条件是:
子进程先退出,父进程还在运行,但父进程没有调用
wait()/waitpid()回收子进程。
此时子进程:
task_struct 结构体Z(Zombie)子进程退出
↓
内核保存退出状态(exit code、信号等)
↓
向父进程发送 SIGCHLD
↓
父进程调用 wait() / waitpid()
↓
子进程彻底消失
如果 父进程不调用 wait(),子进程就会一直保持僵尸状态。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
// 子进程
printf("child exit\n");
exit(0);
} else {
// 父进程
sleep(30); // 不调用 wait()
}
return 0;
}
编译运行后:
ps aux | grep a.out
你会看到类似:
user 12345 0.0 0.0 0 0 ? Z 10:00 0:00 [a.out] <defunct>
其中:
Z:僵尸状态<defunct>:已死进程会,但 bash 等 shell 通常会自动 wait() 子进程,所以很少看到。
例如:
sleep 100 &
当 sleep 结束时,bash 会回收它,不会变成僵尸。
psps aux | grep 'Z'
或:
ps -eo pid,ppid,stat,cmd | grep Z
常见状态:
| 状态 | 含义 |
|---|---|
| Z | 僵尸进程 |
| Z+ | 前台僵尸 |
top在 top 中:
S 列看到 Zzombie 数量✅ 不会占用 CPU、内存 ❌ 会占用 PID
危害主要体现在:
kill -9 <zombie_pid>
❌ 无效
原因:
僵尸进程已经死了,kill 只能作用于“活进程”
wait(NULL);
或:
waitpid(-1, NULL, WNOHANG);
父进程退出后,僵尸进程会被 init(PID 1)接管并回收
kill 父进程PID
signal(SIGCHLD, SIG_IGN);
适用场景有限,不建议新手使用。
✅ 创建子进程后:
wait()sigaction + SA_NOCLDWAIT✅ 守护进程:
僵尸进程是“父进程不负责回收子进程退出状态”的副产品,不是系统 bug,而是程序设计问题。
如果你愿意,我可以: