一個(gè)進(jìn)程在調(diào)用exit命令結(jié)束自己的生命的時(shí)候,其實(shí)它并沒(méi)有真正的被銷(xiāo)毀,而是留下一個(gè)稱為僵尸進(jìn)程(Zombie)的數(shù)據(jù)結(jié)構(gòu)(系統(tǒng)調(diào)用exit,它的作用是使進(jìn)程退出,但也僅僅限于將一個(gè)正常的進(jìn)程變成一個(gè)僵尸進(jìn)程,并不能將其完全銷(xiāo)毀)。
在Linux進(jìn)程的狀態(tài)中,僵尸進(jìn)程是非常特殊的一種,它已經(jīng)放棄了幾乎所有內(nèi)存空間,沒(méi)有任何可執(zhí)行代碼,也不能被調(diào)度,僅僅在進(jìn)程列表中保留一個(gè)位置,記載該進(jìn)程的退出狀態(tài)等信息供其他進(jìn)程收集,除此之外,僵尸進(jìn)程不再占有任何內(nèi)存空間。它需要它的父進(jìn)程來(lái)為它收尸,如果他的父進(jìn)程沒(méi)安裝SIGCHLD信號(hào)處理函數(shù)調(diào)用wait或waitpid()等待子進(jìn)程結(jié)束,又沒(méi)有顯式忽略該信號(hào),那么它就一直保持僵尸狀態(tài),如果這時(shí)父進(jìn)程結(jié)束了,那么init進(jìn)程自動(dòng)
會(huì)接手這個(gè)子進(jìn)程,為它收尸,它還是能被清除的。但是如果如果父進(jìn)程是一個(gè)循環(huán),不會(huì)結(jié)束,那么子進(jìn)程就會(huì)一直保持僵尸狀態(tài),這就是為什么系統(tǒng)中有時(shí)會(huì)有很多的僵尸進(jìn)程。
怎么查看僵尸進(jìn)程:
利用命令ps,可以看到有標(biāo)記為Z的進(jìn)程就是僵尸進(jìn)程。
先看段代碼
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h>
int main(int argc, char** argv) { int num = 6; pid_t pid; if((pid=fork())<0) { printf("fork error\n"); return -1; } else if(pid==0) { num += 2; printf("this is child %d,parent %d, num is %d\n", getpid(), getppid(), num); exit(0); }
sleep(1); printf("this is %d,parent %d, num is %d\n", getpid(), getppid(), num); system("ps -o pid,ppid,state,tty,command"); return 0; }
|
輸出
this is child 3647,parent 3646, num is 8
PID PPID S TT COMMAND
3077 3028 S pts/2 bash
3646 3077 S pts/2 ./zombie
3647 3646 Z pts/2 [zombie] <defunct>
3649 3646 R pts/2 ps -o pid,ppid,state,tty,command
this is 3646,parent 3077, num is 6
看到了,這就是個(gè)zombie
怎樣來(lái)避免僵尸進(jìn)程:
1.改寫(xiě)父進(jìn)程,在子進(jìn)程死后要為它收尸。具體做法是接管SIGCHLD信號(hào)。子進(jìn)程死后,會(huì)發(fā)送SIGCHLD信號(hào)給父進(jìn)程,父進(jìn)程收到此信號(hào)后,執(zhí)行waitpid()函數(shù)為子進(jìn)程收尸。這是基于這樣的原理:就算父進(jìn)程沒(méi)有調(diào)用wait,內(nèi)核也會(huì)向它發(fā)送SIGCHLD消息,盡管對(duì)的默認(rèn)處理是忽略,如果想響應(yīng)這個(gè)消息,可以設(shè)置一個(gè)處理函數(shù)。
2.把父進(jìn)程殺掉。父進(jìn)程死后,僵尸進(jìn)程成為"孤兒進(jìn)程",過(guò)繼給1號(hào)進(jìn)程init,init始終會(huì)負(fù)責(zé)清理僵尸進(jìn)程.它產(chǎn)生的所有僵尸進(jìn)程也跟著消失。
#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h>
int main(int argc, char** argv) { int num = 6; pid_t pid; if((pid=fork())<0) { printf("fork error\n"); return -1; } else if(pid==0) { #if 1 if((pid=fork())<0) { printf("fork error\n"); return -1; } else if(pid>0) exit(0); sleep(1); #endif num += 2; printf("this is child %d,parent %d, num is %d\n", getpid(), getppid(), num); exit(0); } #if 1 if(waitpid(pid, NULL, 0)!=pid) { printf("waitpid error\n"); return -1; } #endif sleep(1); printf("this is %d,parent %d, num is %d\n", getpid(), getppid(), num); //while(1)
//;
system("ps -o pid,ppid,state,tty,command"); return 0; }
|
輸出
this is child 3629,parent 1, num is 8
PID PPID S TT COMMAND
3077 3028 S pts/2 bash
3627 3077 S pts/2 ./zombie
3630 3627 R pts/2 ps -o pid,ppid,state,tty,command
this is 3627,parent 3077, num is 6
waitpid為第一個(gè)子進(jìn)程收死,避免第一個(gè)子進(jìn)程為zombie,而孫進(jìn)程則由交給init了,
this is child 3629,parent 1, num is 8
于是就沒(méi)有state為Z的zombie了!!!!!
《轉(zhuǎn)自》http://blog.chinaunix.net/u2/76292/showart.php?id=2064840
posted on 2009-10-06 23:42
chatler 閱讀(553)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
Linux_Coding