轉(zhuǎn)載:https://www.cnblogs.com/Anker/p/3271773.html
1钾军、前言
之前在看《unix環(huán)境高級編程》第八章進程時候斜脂,提到孤兒進程和僵尸進程求晶,一直對這兩個概念比較模糊手负。今天被人問到什么是孤兒進程和僵尸進程某弦,會帶來什么問題,怎么解決涣觉,我只停留在概念上面联喘,沒有深入,倍感慚愧载庭。晚上回來google了一下看彼,再次參考APUE,認真總結(jié)一下昧捷,加深理解闲昭。
2、基本概念
我們知道在unix/linux中靡挥,正常情況下序矩,子進程是通過父進程創(chuàng)建的,子進程在創(chuàng)建新的進程跋破。子進程的結(jié)束和父進程的運行是一個異步過程,即父進程永遠無法預(yù)測子進程 到底什么時候結(jié)束簸淀。當一個 進程完成它的工作終止之后,它的父進程需要調(diào)用wait()或者waitpid()系統(tǒng)調(diào)用取得子進程的終止狀態(tài)毒返。
孤兒進程:一個父進程退出租幕,而它的一個或多個子進程還在運行,那么那些子進程將成為孤兒進程拧簸。孤兒進程將被init進程(進程號為1)所收養(yǎng)劲绪,并由init進程對它們完成狀態(tài)收集工作。
僵尸進程:一個進程使用fork創(chuàng)建子進程盆赤,如果子進程退出贾富,而父進程并沒有調(diào)用wait或waitpid獲取子進程的狀態(tài)信息,那么子進程的進程描述符仍然保存在系統(tǒng)中牺六。這種進程稱之為僵死進程颤枪。
3、問題及危害
unix提供了一種機制可以保證只要父進程想知道子進程結(jié)束時的狀態(tài)信息淑际, 就可以得到畏纲。這種機制就是: 在每個進程退出的時候,內(nèi)核釋放該進程所有的資源,包括打開的文件,占用的內(nèi)存等扇住。 但是仍然為其保留一定的信息(包括進程號the process ID,退出狀態(tài)the termination status of the process,運行時間the amount of CPU time taken by the process等)。直到父進程通過wait / waitpid來取時才釋放盗胀。 但這樣就導(dǎo)致了問題艘蹋,如果進程不調(diào)用wait / waitpid的話,?那么保留的那段信息就不會釋放票灰,其進程號就會一直被占用簿训,但是系統(tǒng)所能使用的進程號是有限的,如果大量的產(chǎn)生僵死進程米间,將因為沒有可用的進程號而導(dǎo)致系統(tǒng)不能產(chǎn)生新的進程. 此即為僵尸進程的危害,應(yīng)當避免膘侮。
孤兒進程是沒有父進程的進程屈糊,孤兒進程這個重任就落到了init進程身上,init進程就好像是一個民政局琼了,專門負責(zé)處理孤兒進程的善后工作逻锐。每當出現(xiàn)一個孤兒進程的時候,內(nèi)核就把孤 兒進程的父進程設(shè)置為init雕薪,而init進程會循環(huán)地wait()它的已經(jīng)退出的子進程昧诱。這樣,當一個孤兒進程凄涼地結(jié)束了其生命周期的時候所袁,init進程就會代表黨和政府出面處理它的一切善后工作盏档。因此孤兒進程并不會有什么危害。
任何一個子進程(init除外)在exit()之后燥爷,并非馬上就消失掉蜈亩,而是留下一個稱為僵尸進程(Zombie)的數(shù)據(jù)結(jié)構(gòu),等待父進程處理前翎。這是每個 子進程在結(jié)束時都要經(jīng)過的階段稚配。如果子進程在exit()之后,父進程沒有來得及處理港华,這時用ps命令就能看到子進程的狀態(tài)是“Z”道川。如果父進程能及時 處理,可能用ps命令就來不及看到子進程的僵尸狀態(tài)立宜,但這并不等于子進程不經(jīng)過僵尸狀態(tài)冒萄。 ?如果父進程在子進程結(jié)束之前退出,則子進程將由init接管赘理。init將會以父進程的身份對僵尸狀態(tài)的子進程進行處理宦言。
僵尸進程危害場景:
例如有個進程,它定期的產(chǎn) 生一個子進程商模,這個子進程需要做的事情很少奠旺,做完它該做的事情之后就退出了蜘澜,因此這個子進程的生命周期很短,但是响疚,父進程只管生成新的子進程鄙信,至于子進程 退出之后的事情,則一概不聞不問忿晕,這樣装诡,系統(tǒng)運行上一段時間之后,系統(tǒng)中就會存在很多的僵死進程践盼,倘若用ps命令查看的話鸦采,就會看到很多狀態(tài)為Z的進程。 嚴格地來說咕幻,僵死進程并不是問題的根源渔伯,罪魁禍首是產(chǎn)生出大量僵死進程的那個父進程。因此肄程,當我們尋求如何消滅系統(tǒng)中大量的僵死進程時锣吼,答案就是把產(chǎn)生大 量僵死進程的那個元兇槍斃掉(也就是通過kill發(fā)送SIGTERM或者SIGKILL信號啦)。槍斃了元兇進程之后蓝厌,它產(chǎn)生的僵死進程就變成了孤兒進 程玄叠,這些孤兒進程會被init進程接管,init進程會wait()這些孤兒進程拓提,釋放它們占用的系統(tǒng)進程表中的資源读恃,這樣,這些已經(jīng)僵死的孤兒進程 就能瞑目而去了崎苗。
3狐粱、僵尸進程解決辦法
(1)通過信號機制
子進程退出時向父進程發(fā)送SIGCHILD信號,父進程處理SIGCHILD信號胆数。在信號處理函數(shù)中調(diào)用wait進行處理僵尸進程肌蜻。
(2)fork兩次
《Unix 環(huán)境高級編程》8.6節(jié)說的非常詳細。原理是將子進程成為孤兒進程必尼,從而其的父進程變?yōu)閕nit進程蒋搜,通過init進程可以處理僵尸進程。測試程序如下所示: