概述
是指子進程退出時,父進程并未對其發出的SIGCHLD信号進行适當處理,導緻子進程停留在僵死狀态等待其父進程為其收屍,這個狀态下的子進程就是僵死進程。
清除
怎樣來清除僵屍進程:
1.改寫父進程,在子進程死後要為它收屍。具體做法是接管SIGCHLD信号。子進程死後,會發送SIGCHLD信号給父進程,父進程收到此信号後,執行waitpid()函數為子進程收屍。這是基于這樣的原理:就算父進程沒有調用wait,内核也會向它發送SIGCHLD消息,盡管對的默認處理是忽略,如果想響應這個消息,可以設置一個處理函數。
2.把父進程殺掉。父進程死後,僵屍進程成為"孤兒進程",過繼給1号進程init,init始終會負責清理僵屍進程.它産生的所有僵屍進程也跟着消失。
在Linux
在Linux中可以用
psauwx
發現僵屍進程
aallw/tty,includingotherusers所有窗口和終端,包括其他用戶的進程
uuser-oriented面向用戶(用戶友好)
-w,wwideoutput寬格式輸出
xprocessesw/ocontrollingttys
在僵屍進程後面會标注
psaxf
看進程樹,以樹形方式現實進程列表
psaxm
會把線程列出來,在linux下進程和線程是統一的,是輕量級進程的兩種方式。
psaxu
顯示進程的詳細狀态
killall
kill-15
kill-9
一般都不能殺掉defunct進程
用了kill-15,kill-9以後之後反而會多出更多的僵屍進程
kill-killpid
fuser-kpid
可以考慮殺死他的parentprocess,kill-9他的parentprocess
一個已經終止,但是其父進程尚未對其進行善後處理(獲取終止子進程的有關信息、釋放它仍占用的資源)的進程被稱為僵死進程(ZombieProcess)。
避免zombie的方法:
1)在SVR4中,如果調用signal或sigset将SIGCHLD的配置設置為忽略,則不會産生僵死子進程。另外,使用SVR4版的sigaction,則可設置SA_NOCLDWAIT标志以避免子進程僵死。
Linux中也可使用這個,在一個程序的開始調用這個函數
signal(SIGCHLD,SIG_IGN);
2)調用fork兩次。程序8-5實現了這一點。
3)用waitpid等待子進程返回.
zombie進程是僵死進程。防止它的辦法,一是用wait,waitpid之類的函數獲得
進程的終止狀态,以釋放資源。另一個是fork兩次
defunct進程隻是在processtable裡還有一個記錄,其他的資源沒有占用,除非你的系統的process個數的限制已經快超過了,zombie進程不會有更多的壞處。
可能唯一的方法就是reboot系統可以消除zombie進程。
任何程序都有僵屍狀态,它占用一點内存資源(也就是進程表裡還有一個記錄),僅僅是表象而已不必害怕。如果程序有問題有機會遇見,解決大批量僵屍簡單有效的辦法是重起。kill是無任何效果的
fork與zombie/defunct"
在Unix下的一些進程的運作方式。當一個進程死亡時,它并不是完全的消失了。進程終止,它不再運行,但是還有一些殘留的小東西等待父進程收回。這些殘留的東西包括子進程的返回值和其他的一些東西。當父進程fork()一個子進程後,它必須用wait()或者waitpid()等待子進程退出。正是這個wait()動作來讓子進程的殘留物消失。
自然的,在上述規則之外有個例外:父進程可以忽略SIGCLD軟中斷而不必要wait()。可以這樣做到(在支持它的系統上,比如Linux):
main()
{
signal(SIGCLD,SIG_IGN);/*nowIdon'thavetowait()!*/
.
.
fork();
fork();
fork();/*Rabbits,rabbits,rabbits!*/
}
現在,子進程死亡時父進程沒有wait(),通常用ps可以看到它被顯示為“”。它将永遠保持這樣直到父進程wait(),或者按以下方法處理。
這裡是你必須知道的另一個規則:當父進程在它wait()子進程之前死亡了(假定它沒有忽略SIGCLD),子進程将把init(pid1)進程作為它的父進程。如果子進程工作得很好并能夠控制,這并不是問題。但如果子進程已經是defunct,我們就有了一點小麻煩。看,原先的父進程不可能再wait(),因為它已經消亡了。這樣,init怎麼知道wait()這些zombie進程。
答案:不可預料的。在一些系統上,init周期性的破壞掉它所有的defunct進程。在另外一些系統中,它幹脆拒絕成為任何defunct進程的父進程,而是馬上毀滅它們。如果你使用上述系統的一種,可以寫一個簡單的循環,用屬于init的defunct進程填滿進程表。這大概不會令你的系統管理員很高興吧?
你的任務:确定你的父進程不要忽略SIGCLD,也不要wait()它fork()的所有進程。不過,你也未必要總是這樣做(比如,你要起一個daemon或是别的什麼東西),但是你必須小心編程,如果你是一個fork()的新手。另外,也不要在心理上有任何束縛。
總結:
子進程成為defunct直到父進程wait(),除非父進程忽略了SIGCLD。
更進一步,父進程沒有wait()就消亡(仍假設父進程沒有忽略SIGCLD)的子進程(活動的或者defunct)成為init的子進程,init用重手法處理它們。