來源:http://www.cnblogs.com/dongzhiquan/archive/2012/07/12/2588906.html
在每個進程退出的時候,內核釋放該進程所有的資源,包括打開的文件,占用的內存等.但是仍然為其保留一定的信息(包括進程號the process ID,退出狀態the termination status of the process,運行時間the amount of CPU time taken by the process等),直到父進程通過wait / waitpid來取時才釋放,此時該進程便成為僵屍進程。
1.什么是僵屍進程?
UNIX 系統中,一個進程結束了,但是他的父進程沒有等待(調用wait / waitpid)他,而父進程還沒有結束,那么他將變成一個僵屍進程.
如果該進程的父進程已經先結束了,那么該進程就不會變成僵屍進程,因為每個進程結束的時候,系統都會掃描當前系統中所運行的所有進程,看有沒有哪個進程是 剛剛結束的這個進程的子進程,如果是的話,就由Init來接管他,成為他的父進程,從而保證每個進程都會有一個父進程.而Init進程會自動wait其子 進程,因此被Init接管的所有進程都不會變成僵屍進程.
2.子進程結束后為什么要進入僵屍狀態?
因為父進程可能要取得子進程的退出狀態等信息。
3.僵屍狀態是每個子進程比經過的狀態嗎?
是的。任何一個子進程(init除外)在exit()之后,並非馬上就消失掉,而是留下一個稱為僵屍進程(Zombie)的數據結構,等待父進程處理。這 是每個 子進程在結束時都要經過的階段。如果子進程在exit()之后,父進程沒有來得及處理,這時用ps命令就能看到子進程的狀態是“Z”。如果父進程能及時 處理,可能用ps命令就來不及看到子進程的僵屍狀態,但這並不等於子進程不經過僵屍狀態。
如果父進程在子進程結束之前退出,則子進程將由init接管。init將會以父進程的身份對僵屍狀態的子進程進行處理。
4.如何查看僵屍進程:
$ ps -el
其中,有標記為Z的進程就是僵屍進程
S代表休眠狀態;D代表不可中斷的休眠狀態;R代表運行狀態;Z代表僵死狀態;T代表停止或跟蹤狀態
5.僵屍進程的避免
1、父進程通過wait和waitpid等函數等待子進程結束,這會導致父進程掛起
2. 如果父進程很忙,那么可以用signal函數為SIGCHLD安裝handler,因為子進程結束后,父進程會收到該信號,可以在handler中調用wait回收
3. 如果父進程不關心子進程什么時候結束,那么可以用signal(SIGCHLD, SIG_IGN)通知內核,自己對子進程的結束不感興趣,那么子進程結束后,內核會回收,並不再給父進程發送信號
4. 還有一些技巧,就是fork兩次,父進程fork一個子進程,然后繼續工作,子進程fork一個孫進程后退出,那么孫進程被init接管,孫進程結束后,init會回收。不過子進程的回收還要自己做。
#include "apue.h" #include <sys/wait.h> int main(void) { pid_t pid; if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /**//* first child */ if ((pid = fork()) < 0) err_sys("fork error"); else if (pid > 0) exit(0); /**//* parent from second fork == first child */ /**//* * We're the second child; our parent becomes init as soon * as our real parent calls exit() in the statement above. * Here's where we'd continue executing, knowing that when * we're done, init will reap our status. */ sleep(2); printf("second child, parent pid = %d ", getppid()); exit(0); } if (waitpid(pid, NULL, 0) != pid) /**//* wait for first child */ err_sys("waitpid error"); /**//* * We're the parent (the original process); we continue executing, * knowing that we're not the parent of the second child. */ exit(0); }