一、僵尸进程背景

1. 僵尸进程产生原因:

        僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源

        当一个进程创建了一个子进程时,他们的运行是异步的。即父进程无法预知子进程会在什么时候结束,那么如果父进程很繁忙来不及wait 子进程时,那么当子进程结束时,会丢失子进程的结束时的状态信息,处于这种考虑unix提供了一种机制可以保证只要父进程想知道子进程结束时的信息,它就可以得到。

        这种机制是:在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存。但是仍然保留了一些信息,留下一个称为僵尸进程(Zombie)的数据结构(如进程号pid 退出状态 运行时间等)。这些保留的信息直到进程通过调用wait/waitpid时才会释放。这样就导致了一个问题,如果没有调用wait/waitpid的话,那么保留的信息就不会释放。

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

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

3.僵尸进程会带来什么危害

  • 进程号就会被一直占用了。但系统所能使用的进程号的有限的,如果产生大量的僵尸进程,将导致系统没有可用的进程号而导致系统不能创建进程。所以我们应该避免僵尸进程;
  • 如果子进程表太大,init接管僵尸进程这个过程就会变慢,在init未发现他们之前,僵尸进程依旧会消耗系统的资源;

因此少量的僵尸进程不会带来很大的危害。

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

        是的。 任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。

5.如何处理僵尸进程?

        (1)正常情况下,需要父进程来“收尸”,但是如果父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程后,该僵尸进程无法正常结束,即使是root身份kill -9也不能杀死僵尸进程;

        (2)此时如果僵尸进程的父进程会自动结束那么僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程;

        (3)如果不能自动结束(比如是个循环,不会结束),此时子进程会一直保持僵尸状态,这种情况下只能通过强制杀死父进程的方式消除僵尸进程。