在 Unix系統管理中,當用ps命令觀察進程的執行狀態時,經常看到某些進程的狀態欄為defunct,這就是所謂的“僵屍”進程。“僵屍”進程是一個早已 死亡的進程,但在進程表(processs table)中仍占了一個位置(slot)。由於進程表的容量是有限的,所以,defunct進程不僅占用系統的內存資源,影響系統的性能,而且如果其數 目太多,還會導致系統癱瘓。
我們知道,每個Unix進程在進程表里都有一個進入點(entry),核心程序執行該進程時使用到的一切信息都存儲在進入點。當用ps命令察看系統中的進程信息時,看到的就是進程表中的相關數據。當以fork()系統調用建立一個新的進程后,核心進程就會在進程表中給這個新進程分配一個進入點,然后將相關信息存儲在該進入點所對應的進程表內。這些信息中有一項是其父進程的識別碼。當這個進程走完了自己的生命周期后,它會執行exit()系統調用,此時原來進 程表中的數據會被該進程的退出碼(exit code)、執行時所用的CPU時間等數據所取代,這些數據會一直保留到系統將它傳遞給它的父進程為止。由此可見,defunct進程的出現時間是在子進 程終止后,但是父進程尚未讀取這些數據之前。
defunct進程是不能直接kill -9殺掉的,否則就不叫僵屍進程了。
知道了defunct進程產生的原因,就可以輕易的kill掉defunct進程。
方法有二:
1,重啟服務器電腦,這個是最簡單,最易用的方法,但是如果你服務器電腦上運行有其他的程序,那么這個方法,代價很大。
所以,盡量使用下面一種方法。
2,找到該defunct僵屍進程的父進程,將該進程的父進程殺掉,則此defunct進程將自動消失。
如何找到defunct僵屍進程的父進程?很簡單,一句命令就夠了:ps -ef | grep defunct_process_pid。
在fork()/execve()過程中,假設子進程結束時父進程仍存在,而父進程fork()之前既沒安裝SIGCHLD信號處理函數調用waitpid()等待子進程結束,又沒有顯式忽略該信號,則子進程成為僵屍進程,無法正常結束,此時即使是root身份kill -9也不能殺死僵屍進程。補救辦法是殺死僵屍進程的父進程(僵屍進程的父進程必然存在),僵屍進程成為”孤兒進程”,過繼給1號進程init,init始終會負責清理僵屍進程。
僵屍進程是指的父進程已經退出,而該進程dead之后沒有進程接受,就成為僵屍進程.(zombie)進程。
defunct進程只是在process table里還有一個記錄,其他的資源沒有占用,除非你的系統的process個數的限制已經快超過了,zombie進程不會有更多的壞處。
產生原因:
1.在子進程終止后到父進程調用wait()前的時間里,子進程被稱為zombie。
2.網絡原因有時會引起僵死進程。
解決方法:
1.設置SIGCLD信號為SIG_IGN,系統將不產生僵死進程。
2.用兩次fork(),而且使緊跟的子進程直接退出,是的孫子進程成為孤兒進程,從而init進程將負責清除這個孤兒進程。
怎樣產生僵屍進程的:
一個進程在調用exit命令結束自己的生命的時候,其實它並沒有真正的被銷毀,而是留下一個稱為僵屍進程(Zombie)的數據結構(系統調用exit,它的作用是使進程退出,但也僅僅限於將一個正常的進程變成一個僵屍進程,並不能將其完全銷毀)。在Linux進程的狀態中,僵屍進程是非常特殊的一種,它已經放棄了幾乎所有內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其他進程收集,除此之外,僵屍進程不再占有任何內存空間。它需要它的父進程來為它收屍,如果他的父進程沒安裝SIGCHLD信號處理函數調用wait或waitpid()等待子進程結束,又沒有顯式忽略該信號,那么它就一直保持僵屍狀態,如果這時父進程結束了,那么init進程自動會接手這個子進程,為它收屍,它還是能被清除的。但是如果如果父進程是一個循環,不會結束,那么子進程就會一直保持僵屍狀態,這就是為什么系統中有時會有很多的僵屍進程。