天天看點

Linux的僵屍程序産生原因及解決方法

1. 産生原因:

   在UNIX 系統中,一個程序結束了,但是他的父程序沒有等待(調用wait / waitpid)他,那麼他将變成一個僵屍程序。通過ps指令檢視其帶有defunct的标志。僵屍程序是一個早已死亡的程序,但在程序表 (processs table)中仍占了一個位置(slot)。

   但是如果該程序的父程序已經先結束了,那麼該程序就不會變成僵屍程序。因為每個程序結束的時候,系統都會掃描目前系統中所運作的所有程序,看看有沒有哪個 程序是剛剛結束的這個程序的子程序,如果是的話,就由Init程序來接管他,成為他的父程序,進而保證每個程序都會有一個父程序。而Init程序會自動 wait其子程序,是以被Init接管的所有程序都不會變成僵屍程序。

   2. 原理分析:

   每個Unix程序在程序表裡都有一個進入點(entry),核心程序執 行該程序時使用到的一切資訊都存儲在進入點。當用 ps 指令察看系統中的程序資訊時,看到的就是程序表中的相關資料。當以fork()系統調用建立一個新的程序後,核心程序就會在程序表中給這個新程序配置設定一個 進入點,然後将相關資訊存儲在該進入點所對應的程序表内。這些資訊中有一項是其父程序的識别碼。

   子程序的結束和父程序的運作是一個異步過程,即父程序永遠無法預測子程序到底什麼時候結束。那麼會不會因為父程序太忙來不及 wait 子程序,或者說不知道子程序什麼時候結束,而丢失子程序結束時的狀态資訊呢?不會。因為UNIX提供了一種機制可以保證,隻要父程序想知道子程序結束時的 狀态資訊,就可以得到。這種機制就是:當子程序走完了自己的生命周期後,它會執行exit()系統調用,核心釋放該程序所有的資源,包括打開的檔案,占用 的記憶體等。但是仍然為其保留一定的資訊(包括程序号the process ID,退出碼exit code,退出狀态the terminationstatus of the process,運作時間the amount of CPU time taken by the process等),這些資料會一直保留到系統将它傳遞給它的父程序為止,直到父程序通過wait / waitpid來取時才釋放。

   3.解決方法:

   (1) 父程序通過wait和waitpid等函數等待子程序結束,這會導緻父程序挂起。

   執行wait()或waitpid()系統調用,則子程序在終止後會立即把它在程序表中的資料傳回給父程序,此時系統會立即删除該進入點。在這種情形下就不會産生defunct程序。

   (2) 如果父程序很忙,那麼可以用signal函數為SIGCHLD安裝handler。在子程序結束後,父程序會收到該信号,可以在handler中調用wait回收。

繼續閱讀