孤儿进程和僵尸进程
Contents
其实这两个概念并不难理解,只要明白了以下两个关键点就可以了:
- 除了
init
进程(进程号为1,从名字就能知道负责系统启动后的相关的初始化工作)外,其他所有的进程都有父进程。也就是进程是一个树形结构,树的顶端是init
进程 - 一个进程都会占用系统资源(内存、文件描述符等),当进程结束后就需要由其父进程来释放它占用的资源
- 那么父进程如何释放子进程资源呢?父进程需要通过wait/waitpid等系统调用函数来等待进程结束,并且可以通过这些函数来获取子进程的退出状态(正常退出,信号杀死等等)
孤儿进程
明白了父子进程的关系,那么有一个问题:如果父进程先于子进程终止,子进程的资源岂不是没人来释放了?
对于这种父进程比自身先终止的进程,顾名思义称之为孤儿进程
。
对于孤儿进程,内核自然不会放任不管,内核会将init进程设置为孤儿进程的父进程,美其名曰收养
,从而当此进程退出后由init
来回收其资源。
可以写一个小程序来验证一下:
|
|
在这个小程序中,对于父进程先获取其进程号,为:11552,然后让其休眠1秒。对于子进程,先获取父进程号,此时父进程还未终止,所以取到的父进程号也为:11552。然后让其休眠两秒,2秒过后,父进程已经终止了,再取其父进程号,发现已经是1号进程,也就是init
了。
僵尸进程
我们考虑父子进程的另一种情况:如果父进程还未调用wait族函数来等待并回收子进程资源,子进程就已经终止了,那么子进程的资源会被如何回收?
我们可能会想,内核应该会自动回收……吧?确实,内核会回收该进程的大部分资源,但是内核会在进程表中保留这一条进程记录,它的ID,它的终止状态等信息。为什么要这么做,而不是全部回收呢,因为内核要保留这些信息,以便父进程调用wait函数时能告知子进程已经终止和终止原因。
也就说是,虽然子进程提前终止了,但父进程还可以在终止后通过调用wait族函数来获取子进程终止原因。
这种已经终止但仍然还保留有一条进程记录的进程,就称谓僵尸进程。为什么叫僵尸呢,因为为了保留这条记录以便父进程获知子进程终止状态,这类进程无论如何都杀不死,即使使用的是KILL -9 进程号
也就是发送SIGKILL信号
也不行。
那么我们考虑,如何才能杀死僵尸进程呢? 也很简单:
- 等待其父进程调用wait族函数将其彻底回收
- 将其父进程杀死,这样这个僵尸进程就由
init
进程来接管了,init
就会自动调用wait来将其回收了。
也写个小程序验证一下:
|
|
运行这个程序,会打印出父子进程号,然后父进程就休眠了,而子进程无事可做就终止了。这时候如果通过ps命令查看子进程的状态,就能看到子进程处于Z+
,也就是僵尸状态了。而此时如果杀掉父进程,会发现子进程也不存在了,因为子进程被init回收了。
试试杀掉子进程?没用的,不然怎么叫僵尸呢!
Author JeelyWu
LastMod 2019-07-26