下面談談 defunct 程序,中文翻譯叫殭屍程序。下文整理於網路以及apue一書。
一、什麼是殭屍程序
在unix 系統中,乙個程序結束了,但是他的父程序沒有等待(呼叫wait / waitpid)他,
那麼他將變成乙個殭屍程序。
當用ps命令觀察程序的執行狀態時,看到這些程序的狀態列為defunct。殭屍程序是乙個早已死亡的程序,但在程序表(processs table)中仍佔了乙個位置(slot)。
但是如果該程序的父程序已經先結束了,那麼該程序就不會變成殭屍程序。
因為每個程序結束的時候,系統都會掃瞄當前系統中所執行的所有程序,看
看有沒有哪個程序是剛剛結束的這個程序的子程序,如果是的話,就由init程序
來接管他,成為他的父程序,從而保證每個程序都會有乙個父程序。
而init程序會自動wait其子程序,因此被init接管的所有程序都不會變成殭屍程序。
二、unix下程序的運作方式
每個unix程序在程序表裡都有乙個進入點(entry),核心程序
執行該程序時使用到的一切資訊都儲存在進入點。當用 ps 命令察看系統中的程序資訊時,看到的就是程序表中的相關資料。當以fork()系統呼叫建立乙個新的程序後,核心程序就會在程序表中給這個新程序分配乙個進入點,然後將相關資訊儲存在該進入點所對應的程序表內。這些資訊中有一項是其父程序的識別碼。
子程序的結束和父程序的執行是乙個非同步過程,即父程序永遠無法**子程序
到底什麼時候結束。那麼會不會因為父程序太忙來不及 wait 子程序,或者說不知道
子程序什麼時候結束,而丟失子程序結束時的狀態資訊呢?
不會。因為unix提供了一種機制可以保證,只要父程序想知道子程序結束時的狀態資訊,
就可以得到。這種機制就是:
當子程序走完了自己的生命週期後,它會執行exit()系統呼叫
,核心釋放該程序所有的資源,包括開啟的檔案,占用的記憶體等。
但是仍然為其保留一定的資訊(包括程序號the process id,
退出碼exit code,
退出狀態the termination
status of the process,執行時間the amount of cpu time taken by the process等),
這些資料會一直保留到系統將它傳遞給它的父程序為止,
直到父程序通過wait / waitpid來取時才釋放。
也就是說,
當乙個程序死亡時,它並不是完全的消失了。程序終止,它不再執行,但是還有一些殘留的資料等待父程序收回。當父程序 fork() 乙個子程序後,它必須用 wait() (或者 waitpid())等待子程序退出。正是這個 wait() 動作來讓子程序的殘留資料消失。
三、殭屍程序的危害
如果父程序不呼叫wait / waitpid的話,那麼保留的那段資訊就不會釋放,其程序號就會一直被占用,但是系統的程序表容量是有限的,所能使用的程序號也是有限的,如果大量的產生殭屍程序,將因為沒有可用的程序號而導致系統不能產生新的程序。
所以,defunct程序不僅占用系統的記憶體資源,影響系統的效能,而且如果其數目太多,還會導致系統癱瘓。而且,
由於排程程式無法選中defunct 程序,所以不能用kill命令刪除defunct 程序,惟一的方法只有重啟系統。
四、殭屍程序的產生
如果子程序死亡時父程序沒有 wait(),通常用 ps 可以看到它被顯示為「」,這樣就產生了殭屍程序。它將永遠保持這樣直到父程序 wait()。
由此可見,defunct程序的出現時間是在子程序終止後,但是父程序尚未讀取這些資料之前。利用這一點我們可以用下面的程式建立乙個defunct 程序:
c**
#include
#include
main()
sleep(20);
printf(「parent pid=%d \n」, getpid());
exit(0);
}
當上述程式以後臺的方式執行時,第17行強迫程式睡眠20秒,讓使用者有時間輸入ps -e指令,觀察程序的狀態,我們看到程序表中出現了defunct程序。當父程序執行終止後,再用ps -e命令觀察時,我們會發現defunct程序也隨之消失。這是因為父程序終止後,init 程序會接管父程序留下的這些「孤兒程序」(orphan process),而這些「孤兒程序」執行完後,它在程序表中的進入點將被刪除。如果乙個程式設計上有缺陷,就可能導致某個程序的父程序一直處於睡眠狀態或是陷入死迴圈,父程序沒有wait子程序,也沒有終止以使init接管,該子程序執行結束後就變成了defunct程序,這個defunct 程序可能會一直留在系統中直到系統重新啟動。
在看乙個產生殭屍程序的例子。
子程序要執行的程式test_prog
c**
#include
int main()
return 0;
}
父程序father的**father.c
c**
#include
#include
#include
#include
int main()
else
*/while (1)
return 0;
} }
執行./father,當子程序退出後,由於父程序沒有對它的退出進行關注,會出現殭屍程序
c**
20786 pts/0 00:00:00 father
20787 pts/0 00:00:00 father
總結:子程序成為 defunct 直到父程序 wait(),除非父程序忽略了 sigcld 。更進一步,父程序沒有 wait() 就消亡(仍假設父程序沒有忽略 sigcld )的子程序(活動的或者 defunct)成為 init 的子程序,init 著手處理它們。
五、如何避免殭屍程序
1、父程序通過wait和waitpid等函式等待子程序結束,這會導致父程序掛起。
2. 如果父程序很忙,那麼可以用signal函式為sigchld安裝handler。在子程序結束後,父程序會收到該訊號,可以在handler中呼叫wait**。
3. 如果父程序不關心子程序什麼時候結束,那麼可以用
signal(sigcld, sig_ign)或
signal(sigchld, sig_ign)通知核心,自己對子程序的結束不感興趣,那麼子程序結束後,核心會**,並不再給父程序傳送訊號
4. fork兩次,父程序fork乙個子程序,然後繼續工作,子程序fork乙個孫程序後退出,那麼孫程序被init接管,孫程序結束後,init會**。不過子程序的**還要自己做。 下面就是stevens給的採用兩次folk避免殭屍程序的示例:
c**
#include "apue.h"
#include
intmain(void)
... else
if (pid == 0) ...
if (waitpid(pid, null, 0) != pid) /**/
/* wait for first child */
err_sys("waitpid error");
/**/
/** we're the parent (the original process); we continue executing,
* knowing that we're not the parent of the second child.
*/exit(0);
}
Defunct 程序 殭屍程序
下面談談 defunct 程序,中文翻譯叫殭屍程序。下文整理於網路以及apue一書。一 什麼是殭屍程序 在unix 系統中,乙個程序結束了,但是他的父程序沒有等待 呼叫wait waitpid 他,那麼他將變成乙個殭屍程序。當用ps命令觀察程序的執行狀態時,看到這些程序的狀態列為defunct。殭屍...
Defunct程序 殭屍程序
下面談談 defunct 程序,中文翻譯叫殭屍程序。下文整理於網路以及apue一書。一 什麼是殭屍程序 在unix 系統中,乙個程序結束了,但是他的父程序沒有等待 呼叫wait waitpid 他,那麼他將變成乙個殭屍程序。當用ps命令觀察程序的執行狀態時,看到這些程序的狀態列為defunct。殭屍...
檢視並殺死defunct殭屍程序
defunct程序如何直接kill掉 只要殺死它的父程序,defunct程序就自動消失了.檢視defunct程序 ps e o ppid,stat grep z cut d f1 殺死ps e o ppid,stat grep z cut d f1 xargs kill 9 defunct程序的產生...