孤儿进程和僵尸进程
孤儿进程和僵尸进程
首先明确系统引导后启动的第一个进程是init进程,PID=1,之后的每个进程都是它的子进程。
孤儿进程
孤儿进程:父进程退出,而子进程还在运行,则子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为init,而init进程会循环地wait()
它的已经退出的子进程。因此孤儿进程并不会有什么危害。
僵尸进程
僵尸进程:由于子进程的结束和父进程的运行是异步的(除非父进程调用wait()
或waitpid()
)子进程退出,而父进程并没有调用wait()
或waitpid()
回收子进程资源,那么子进程的进程描述符(包括PID、退出状态,运行时间等)仍然保存在系统中,该子进程成为僵尸进程。
在学习操作系统中进程的终止时提到OS不会立刻将进程的全部信息清除,而是先保留一会等待其他进程收集。
如果进程不调用
wait()
或waitpid()
的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。
注意:每个子进程在结束(调用exit()
)后,会留下一个僵尸进程(Zombie)的数据结构,等待父进程处理,父进程处理完这个数据结构后,子进程才会真正消失。
如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。
解决僵尸进程:僵尸进程已经“死了”,不能再死一次(因此无法使用kill -9
杀死僵尸进程),其产生危害的原因是父进程没有为其善后处理。因此解决方案是kill掉父进程,从而让僵尸进程成为孤儿进程交给init进程托管。
总结
僵尸进程无人收尸将会导致资源浪费,而孤儿进程有init进程托管则不会造成资源浪费。