Linux 孤儿进程与僵尸进程

子进程的结束和父进程的运行是异步的——父进程永远无法预测子进程什么时候结束。那么,会不会因为父进程太忙来不及 wait 子进程,或者不知道子进程何时结束,而丢失子进程结束时的状态信息呢?答案是:不会。

UNIX 提供了一种机制来保证:只要父进程想获取子进程结束时的状态信息,就可以得到。这个机制是——每个进程退出时,内核释放该进程所有的资源(打开的文件、占用的内存等),但仍保留一定的信息(包括进程号、退出状态、运行时间等),直到父进程通过 wait/waitpid 来取时才释放。

但这带来了一个问题:如果进程不调用 wait/waitpid,那么保留的信息就不会释放,其进程号会一直被占用。而系统可用的进程号是有限的,如果大量产生僵死进程,就会因为进程号耗尽而导致系统无法产生新进程——这正是僵尸进程的危害,应当避免。

僵尸进程的处理

子进程结束后为什么要进入僵尸状态?

因为父进程可能要取得子进程的退出状态等信息。

僵尸状态是每个子进程必经的状态吗?

是的。任何一个子进程(init 除外)在 exit() 之后,并非马上就消失,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理——这是每个子进程在结束时都要经过的阶段。

如果子进程在 exit() 之后父进程没有来得及处理,这时用 ps 命令就能看到子进程的状态是 “Z”;如果父进程能及时处理,可能就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。

如果父进程在子进程结束之前退出,则子进程由 init 接管,init 会以父进程的身份处理僵尸状态的子进程。

如何查看僵尸进程?

$ ps -el

其中,标记为 Z 的进程就是僵尸进程:

  • S:休眠状态
  • D:不可中断的休眠状态
  • R:运行状态
  • Z:僵死状态
  • T:停止或跟踪状态

僵尸进程变为孤儿进程

父进程死后,僵尸进程成为孤儿进程,过继给 1 号进程 init。init 始终会负责清理僵尸进程,它产生的所有僵尸进程也跟着消失。

基本概念

在 Unix/Linux 中,正常情况下子进程由父进程创建,子进程再创建新的进程。当一个进程完成工作终止之后,它的父进程需要调用 wait() 或 waitpid() 系统调用取得子进程的终止状态。

概念 定义
孤儿进程 一个父进程退出,而它的一个或多个子进程还在运行,那些子进程就成为孤儿进程。孤儿进程会被 init 进程(进程号 1)收养,并由 init 完成状态收集
僵尸进程 一个进程用 fork 创建子进程后,如果子进程退出而父进程没有调用 wait/waitpid 获取其状态,那么子进程的进程描述符仍保留在系统中,这种进程称为僵死进程

问题及危害

孤儿进程:孤儿进程是没有父进程的进程,这个责任落到 init 进程身上——每当出现一个孤儿进程,内核就把它的父进程设置为 init,而 init 会循环地 wait() 它已经退出的子进程。因此孤儿进程并不会有什么危害。

僵尸进程的危害场景:例如某个进程定期地产生一个子进程,这个子进程需要做的事情很少,做完就退出,生命周期很短;但父进程只管生成新子进程,对子进程退出之后的事情一概不闻不问。这样运行一段时间后,系统中就会积累大量僵死进程,用 ps 命令能看到很多状态为 Z 的进程。

严格来说,僵死进程并不是问题的根源,罪魁祸首是产生大量僵死进程的那个父进程。因此,要消灭系统中大量的僵死进程,办法就是终止那个”元凶”父进程(通过 kill 发送 SIGTERM 或 SIGKILL 信号)。父进程终止后,它产生的僵死进程就变成孤儿进程,被 init 接管;init 会 wait() 这些孤儿进程,释放它们占用的系统进程表资源,这些僵死进程就随之清理了。

僵尸进程的解决办法

通过信号机制

子进程退出时向父进程发送 SIGCHLD 信号,父进程处理 SIGCHLD 信号,在信号处理函数中调用 wait 处理僵尸进程。

fork 两次

《Unix 环境高级编程》8.6 节有非常详细的说明。原理是将子进程变为孤儿进程,使其父进程变为 init 进程,从而由 init 进程处理僵尸进程。


   转载规则


《Linux 孤儿进程与僵尸进程》 由 吴杭沉 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Linux 僵尸进程的产生与处理 Linux 僵尸进程的产生与处理
可能很少有人意识到,一个进程调用 exit 之后,它并非马上就消失,而是留下一个称为僵尸进程(Zombie)的数据结构。在 Linux 进程的几种状态中,僵尸进程非常特殊:它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅
2020-03-17
下一篇 
Linux 进程状态详解 Linux 进程状态详解
有同事问到 top 命令里的 running、sleep、stop、zombie 等进程状态分别是什么意思,于是借这个机会整理一下 Linux 系统里的进程状态。 概述进程(Process)即当前正在运行的计算机程序的实例。每个进程都有一些
2020-02-20
  目录