孤儿进程是指在进程还未退出之前它的父进程就已经先退出了,简单来说就是一个没有父进程的子进程就是孤儿进程。既然所有的进程都必须在退出之后被父进程的wait()或waitpid()以释放其遗留在系统中的一些资源,那么孤儿进程的这些东西又谁来处理呢?这个任务就落到了init进程的身上,init进程就好像一个收纳所,每当内核发现一个孤儿进程,就会把孤儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。所以这样看来孤儿进程并不会危害系统的运行。
Linux进程模型中,进程是按照父进程产生子进程,子进程再产生子子进程这样的方式创建出完成各项相互协作功能的进程的。当一个进程完成它的工作,终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。但是如果父进程没有这样做的话会产生什么后果呢?此时,子进程虽然已经退出了,但是在系统进程表中还未它保留了一些退出状态信息,如果父进程没有这么做的话会产生什么后果呢?
如果子进程在没有被父进程的wait()和waitpid()调用的情况下退出,那么子进程的退出状态信息就会一直占用着进程状态表的表项,这个时候这些进程就被称为僵尸进程。
如下代码fork()了一个子进程根据子进程fork中返回0,父进程中fork返回子进程pid的特性,使子进程很快就退出了,而父进程一直处于sleep状态,这样就产生了僵尸进程。
#include<stdio.h> #include<unistd.h> int main() { int pid = fork(); if(pid > 0) { while(1) { sleep(3); } } else if(pid == 0) { printf("Zombie Progress"); exit(0); } }这里使用ps指令查看进程状态如图所示,可以看成11943号进程状态为Z,代表它就是一个僵尸进程
系统进程表是一项有限资源,如果系统进程表被僵尸进程耗尽的话,系统就可能无法创建新的进程。 例如有这样一个父进程,它定期会产生一个子进程,这个子进程的生命周期比较短,运行不了多久就会退出,而父进程会不断的产生新的子进程,确又不在进程退出之后对其退出状态进行处理,那么系统运行上一段时间之后就会出现很多的僵尸进程,导致无法创建新的进程。那么我们如何处理这些僵尸进程呢? 其实这里问题的根源不是这些僵尸进程自身,而是不断产生这些僵尸进程的父进程,所以我们的解决方案就是杀死这个父进程。当我们杀掉这个父进程之后,他产生的这些僵尸进程就会变成孤儿进程,而孤儿进程又会被init的wait()释放退出状态信息。这样就解决了僵尸进程占用系统进程表的问题了。当然这是不得已而为之的方法,最好是在代码中就对其进行控制,防止僵尸进程的产生。