温馨提示×

ubuntu 僵尸进程怎么产生

小樊
41
2026-07-27 12:45:00
栏目: 智能运维

僵尸进程(Zombie Process)在 Ubuntu(以及所有 Linux 系统)中,本质上是子进程已经结束,但父进程还没有回收它的退出状态而产生的一种“已死但未彻底消失”的进程。

下面从产生原因、原理、示例、查看和避免方法几个方面说明。


一、僵尸进程是怎么产生的?

1️⃣ 产生条件(重点)

僵尸进程产生的必要条件是:

子进程先退出,父进程还在运行,但父进程没有调用 wait() / waitpid() 回收子进程。

此时子进程:

  • 已经执行完毕或被信号终止
  • 进程体已经释放
  • 只保留一个 task_struct 结构体
  • 状态变为 Z(Zombie)

2️⃣ 进程退出时的基本流程

子进程退出
   ↓
内核保存退出状态(exit code、信号等)
   ↓
向父进程发送 SIGCHLD
   ↓
父进程调用 wait() / waitpid()
   ↓
子进程彻底消失

如果 父进程不调用 wait(),子进程就会一直保持僵尸状态。


二、僵尸进程示例(C 语言)

#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>:已死进程

三、shell 中也会产生僵尸吗?

会,但 bash 等 shell 通常会自动 wait() 子进程,所以很少看到。

例如:

sleep 100 &

sleep 结束时,bash 会回收它,不会变成僵尸


四、如何查看僵尸进程?

1️⃣ 使用 ps

ps aux | grep 'Z'

或:

ps -eo pid,ppid,stat,cmd | grep Z

常见状态:

状态 含义
Z 僵尸进程
Z+ 前台僵尸

2️⃣ 使用 top

top 中:

  • S 列看到 Z
  • 或看 zombie 数量

五、僵尸进程有什么危害?

不会占用 CPU、内存会占用 PID

危害主要体现在:

  • PID 被耗尽(极端情况下)
  • 父进程存在时间很长(如守护进程、服务程序)

六、僵尸进程为什么杀不掉?

kill -9 <zombie_pid>

无效

原因:

僵尸进程已经死了,kill 只能作用于“活进程”


七、如何正确处理僵尸进程?

✅ 方法 1:让父进程回收(推荐)

wait(NULL);

或:

waitpid(-1, NULL, WNOHANG);

✅ 方法 2:父进程退出

父进程退出后,僵尸进程会被 init(PID 1)接管并回收

kill 父进程PID

✅ 方法 3:忽略 SIGCHLD(不推荐,有坑)

signal(SIGCHLD, SIG_IGN);

适用场景有限,不建议新手使用。


八、如何避免僵尸进程(开发建议)

✅ 创建子进程后:

  • 一定要 wait()
  • 或使用 sigaction + SA_NOCLDWAIT
  • 或设计成“短生命周期父进程”

✅ 守护进程:

  • 正确处理子进程退出
  • 不要忽略异常处理

九、一句话总结

僵尸进程是“父进程不负责回收子进程退出状态”的副产品,不是系统 bug,而是程序设计问题。

如果你愿意,我可以:

  • 帮你分析某个真实僵尸进程
  • 给你 Python / Go / Shell 的示例
  • 讲 init / systemd 如何回收孤儿进程

0