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
  目录