Linux 03:僵死进程(Zombie Process)原理、危害与解决方案

一、什么是僵死进程(Zombie Process)?

僵死进程 :子进程先于父进程退出,但父进程没有调用 wait () /waitpid () 来回收子进程的退出状态与资源,导致子进程虽然已经停止运行,但进程描述符依然保留在系统进程表中 ,无法被彻底释放,这种状态的进程就叫 僵死进程

简单一句话:子进程死了,尸体没人收,就变成了僵尸。

僵死进程的标志

ps 命令中,状态列为:

复制代码
Z+

Z = Zombie(僵尸)


二、为什么会产生僵死进程?

Linux 设计规则:

  1. 子进程退出时,不会直接消失
  2. 内核会保留子进程的退出码、运行时间等信息
  3. 必须由父进程通过 wait() / waitpid() 读取并释放
  4. 如果父进程不读取 → 子进程变成僵尸

三、产生僵死进程的代码示例(最经典)

下面这段代码会强制制造僵死进程

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    pid_t pid = fork(); // 创建子进程

    if (pid == 0) {
        // 子进程
        printf("子进程 PID = %d 开始运行\n", getpid());
        printf("子进程退出,即将变成僵尸...\n");
        return 0; // 子进程立刻退出
    }
    else {
        // 父进程
        printf("父进程 PID = %d\n", getpid());
        while (1) { // 父进程死循环,不回收子进程
            sleep(1);
        }
    }
}

运行结果

复制代码
父进程 PID = 1234
子进程 PID = 1235 开始运行
子进程退出,即将变成僵尸...

此时子进程已经退出,但父进程死循环不回收 → 子进程变成僵死进程


四、如何查看僵死进程?

方法 1:ps 命令

bash 复制代码
ps aux | grep Z

看到 Z+ 就是僵尸进程。

方法 2:查看系统僵尸总数

bash 复制代码
top

查看 Zombie 那一行数字。


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

  1. **占用进程号(PID)**系统 PID 数量有限,大量僵尸会导致无法创建新进程。
  2. 占用内核内存进程描述符、task_struct 结构不会释放。
  3. 严重时导致系统宕机

**注意:普通 kill 命令杀不死僵尸进程!**因为它已经 "死了",只是尸体没清理。


六、如何解决 / 避免僵死进程?(3 种最常用方案)

方案 1:父进程调用 wait () 阻塞等待回收(最简单)

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        printf("子进程 %d 运行并退出\n", getpid());
        return 0;
    } else {
        wait(NULL); // 父进程阻塞等待子进程退出并回收
        printf("父进程成功回收子进程!\n");
        while(1) sleep(1);
    }
}

无僵尸进程


方案 2:使用 waitpid () 非阻塞回收(推荐)

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        printf("子进程 %d 退出\n", getpid());
        return 0;
    } else {
        // 非阻塞轮询回收
        while (waitpid(pid, NULL, WNOHANG) == 0) {
            printf("父进程工作中...\n");
            sleep(1);
        }
        printf("子进程已回收\n");
    }
    return 0;
}

方案 3:用信号机制 SIGCHLD 异步回收(企业级)

子进程退出时,内核会向父进程发送 SIGCHLD 信号

父进程捕获信号,在信号处理函数中回收。

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

// 信号处理函数:回收僵尸
void handler(int sig) {
    while (waitpid(-1, NULL, WNOHANG) > 0);
}

int main() {
    signal(SIGCHLD, handler); // 注册信号

    pid_t pid = fork();
    if (pid == 0) {
        printf("子进程 %d 退出\n", getpid());
        return 0;
    } else {
        while (1) {
            printf("父进程运行中...\n");
            sleep(1);
        }
    }
}

完全无阻塞、无僵尸、企业标准写法


七、已经产生的僵尸进程怎么杀?

两种方法:

方法 1:杀死父进程

父进程死掉后,僵尸子进程会被 init 进程(pid=1) 收养并自动回收。

bash 复制代码
kill -9 父进程PID

方法 2:重启系统(不推荐)

相关推荐
yang9yun2 小时前
linux宝塔面板使用API自动部署更新文件
linux·运维·状态模式
cen__y2 小时前
Linux06(进程)
linux·运维·服务器·c语言·ubuntu
bruk_spp2 小时前
linux子系统之drm dsi
linux
码银2 小时前
使用VMware安装CentOS7(Linux)操作系统(图文步骤)附vmware安装包/centos.iso镜像文件
linux·运维·centos
似水এ᭄往昔2 小时前
【Linux】--磁盘和文件系统
linux·运维·数据库
hhl_483841042 小时前
上海域格4G模块信号说明
linux·功能测试·物联网·信号处理·tcp
Gofarlic_oms12 小时前
Allegro高级功能模块许可证管理注意事项
运维·服务器·开发语言·matlab·负载均衡
IMPYLH2 小时前
Linux 的 sum 命令
linux·运维·服务器·chrome·python·bash
AIDF20262 小时前
我们看一份报告的时候主要看什么
运维·服务器·推理·vllm