千家信息网

Linux 僵尸进程产生原因及解决方法

发表于:2025-12-01 作者:千家信息网编辑
千家信息网最后更新 2025年12月01日,Linux 允许进程查询内核以获得其父进程的 PID,或者其任何子进程的执行状态。例如,进程可以创建一个子进程来执行特定的任务,然后调用诸如 wait() 这样的一些库函数检查子进程是否终止。如果子进
千家信息网最后更新 2025年12月01日Linux 僵尸进程产生原因及解决方法

Linux 允许进程查询内核以获得其父进程的 PID,或者其任何子进程的执行状态。例如,进程可以创建一个子进程来执行特定的任务,然后调用诸如 wait() 这样的一些库函数检查子进程是否终止。如果子进程已经终止,那么,它的终止代号将告诉父进程这个任务是否已成功地完成。

为了遵循这些设计原则,不允许 Linux 内核在进程一终止后就丢弃包含在进程描述符字段中的数据。只有父进程发出了与被终止的进程相关的 wait() 类系统调用之后,才允许这样做。这就是引入僵死状态的原因:尽管从技术上来说进程已死,但必须保存它的描述符,直到父进程得到通知。

如果一个进程已经终止,但是它的父进程尚未调用 wait() 或 waitpid() 对它进行清理,这时的进程状态称为僵死状态,处于僵死状态的进程称为僵尸进程(zombie process)。任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了。

僵尸进程是如何产生的

在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程。通过ps命令查看其带有defunct的标志。僵尸进程是一个早已死亡的进程,但在进程表 (processs table)中仍占了一个位置(slot)。

但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程。因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个 进程是刚刚结束的这个进程的子进程,如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而Init进程会自动 wait其子进程,因此被Init接管的所有进程都不会变成僵尸进程。

为了观察到僵尸进程,我们自己写一个不正常的程序,父进程 fork 出子进程,子进程终止,而父进程既不终止也不调用 wait 清理子进程:

#include #include #include int main(void){  int i = 100;  pid_t pid=fork();  if(pid < 0)  {    perror("fork failed.");    exit(1);  }  if(pid > 0)  {    printf("This is the parent process. My PID is %d.\n", getpid());    for(; i > 0; i--)    {      sleep(1);    }  }  else if(pid == 0)  {    printf("This is the child process. My PID is: %d. My PPID is: %d.\n", getpid(), getppid());  }  return 0;}

把上面的代码保存到文件 zomprocdemo.c 文件中,并执行下面的命令编译:

$ gcc zomprocdemo.c -o zomprocdemo

然后运行编译出来的 zomprocdemo 程序:

$ ./zomprocdemo

此时子进程已经退出,但是父进程没有退出也没有通过 wait() 调用处理子进程。我们使用 ps 命令查看进程的状态:

上图红框中的大写字母 "Z" 说明 PID 为 112712 的进程此时处于僵死的状态。

让我们接着往下看!在结束 sleep 后父进程退出。当父进程退出后,子进程会变成孤儿进程,此时它会被一个管理进程收养。在不同的系统中,这个管理进程不太一样,早期一般是 init 进程,Ubuntu 上是 upstart,还有近来的 Systemd。但是它们都完成相同的任务,就是 wiat() 这些孤儿进程,并最终释放它们占用的系统进程表中的资源。这样,这些已经僵死的孤儿进程就彻底的被清除了。

僵尸进程的危害

在进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号 PID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。

如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。

如何处理僵尸进程

僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要在父进程中通过 wait() 来避免僵尸进程的产生。

当系统中出现了僵尸进程时,我们是无法通过 kill 命令把它清除掉的。但是我们可以杀死它的父进程,让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。

下面的 demo 中,父进程通过 wait() 等待子进程结束:

#include #include #include #include #include int main(void){  pid_t pid;  pid = fork();  if (pid < 0)  {    perror("fork failed");    exit(1);  }  if (pid == 0) {    int i;     for (i = 3; i > 0; i--)     {      printf("This is the child\n");      sleep(1);     }     // exit with code 3 for test.    exit(3);  }  else  {    int stat_val;    wait(&stat_val);     if (WIFEXITED(stat_val))     {       printf("Child exited with code %d\n", WEXITSTATUS(stat_val));     }        }  return 0;}

demo 中父进程不仅等待子进程结束,还通过 WEXITSTATUS 宏取到了子进程的 exit code。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

进程 僵尸 系统 状态 孤儿 命令 任务 内核 就是 文件 程序 面的 管理 运行 信息 时候 资源 进程表 编译 原因 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 山西网络安全人才培养基地 web空间服务器密码是什么 有关软件开发的创业计划书 数据库图片加载不出 办公网络技术方案 联合国对缅甸网络安全法草案 普洱互联网科技怎么样 南沙网络安全建设怎么收费 浙江软件开发价格监测中心 科技互联网发布会视频 关于网络技术发展的实训报告 中储粮集团软件开发人员外派 网络安全法主题宣传课班会 数据库接口方式有哪些 宣传周网络安全知识问答 虎丘区正规服务器代理厂家 阿里大服务器有什么优势 保存到数据库失败 火鸟门户 娄底游戏软件开发 长宁区企业网络技术服务信息推荐 计算机网络技术从哪里学 数据库实体关系识别 网络安全法规英语作文 我的世界建手机版服务器过程 中通吉网络技术有限公司工作 济南做网络安全的公司 矿大网络安全试卷答案 网络技术三级什么时候考试 数据库设置默认表空间 衢州软件开发
0