以下內容有一部分摘自百度百科,一部分摘自《UNIX環境高級編程》
一個進程在調用exit命令結束自己的生命的時候,其實它並沒有真正的被銷毀,而是留下一個稱為僵屍進程(Zombie)的數據結構(系統調用exit,它的作用是使進程退出,但也僅僅限於將一個正常的進程變成一個僵屍進程,並不能將其完全銷毀)。在Linux進程的狀態中,僵屍進程是非常特殊的一種,它已經放棄了幾乎所有內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其他進程收集,除此之外,僵屍進程不再占有任何內存空間。它需要它的父進程來為它收屍,如果他的父進程沒安裝SIGCHLD信號處理函數調用wait或waitpid()等待子進程結束,又沒有顯式忽略該信號,那么它就一直保持僵屍狀態,如果這時父進程結束了,那么init進程自動會接手這個子進程,為它收屍,它還是能被清除的。但是如果父進程是一個循環,不會結束,那么子進程就會一直保持僵屍狀態,這就是為什么系統中有時會有很多的僵屍.
怎么查看僵屍進程:
利用命令ps,可以看到有標記為Z的進程就是僵屍進程。
怎樣來清除僵屍進程:
1.改寫父進程,在子進程死后要為它收屍。具體做法是接管SIGCHLD信號。子進程死后,會發送SIGCHLD信號給父進程,父進程收到此信號后,執行waitpid()函數為子進程收屍。這是基於這樣的原理:就算父進程沒有調用wait,內核也會向它發送SIGCHLD消息,盡管默認處理是忽略,如果想響應這個消息,可以設置一個處理函數。
2.把父進程殺掉。父進程死后,僵屍進程成為"孤兒進程",過繼給1號進程init,init始終會負責清理僵屍進程.它產生的所有僵屍進程也跟着消失。
如果一個進程fork一個子進程,但不要等它等待子進程終止,也不希望子進程處於僵死狀態直到父進程終止.要實現這個要求,《UNIX環境高級編程》提供了一個十分
巧妙的方法,代碼如下
1 #include<sys/types.h> 2 #include<sys/wait.h> 3 #include<fcntl.h> 4 #include<stdio.h> 5 int main() 6 { 7 pid_t pid; 8 if((pid= fork()) <0 ) 9 perror("fork error"); 10 else if(pid==0) 11 { 12 if( (pid=fork())<0 ) 13 perror("fork error"); 14 else if(pid>0) 15 exit(0);/*parent from second fork == first child*/ 16 /*we're the second child;our parent becomes init as soon as 17 our real parent calls exit() in the statement above. 18 Here's where we'd continue executing,knowing that when we're 19 done,init will reap our status. */ 20 sleep(2); 21 printf("second child,parent pid=%d\n",getppid() ); 22 exit(0); 23 } 24 if(waitpid(pid,NULL,0) !=pid)/*wait for first child waitpid函數返回終止子進程的進程ID,第三個參數一般為0 或者是其他選擇項*/ 25 perror("waitpid error"); 26 /*we're the parent (the original process); we continue executing. 27 knowing that we're not the parent of the second child.*/ 28 exit(0); 29 }
大家慢慢品味這個程序的巧妙吧,俺道破了就沒有什么意思了,你們也會少了很多樂趣