1. 程式人生 > >Kill殺死Linux中的defunct程序(殭屍程序)

Kill殺死Linux中的defunct程序(殭屍程序)

一、什麼是defunct程序(殭屍程序)?
在 Linux 系統中,一個程序結束了,但是他的父程序沒有等待(呼叫wait / waitpid)他,那麼他將變成一個殭屍程序。當用ps命令觀察程序的執行狀態時,看到這些程序的狀態列為defunct。殭屍程序是一個早已死亡的程序,但在程序表(processs table)中仍佔了一個位置(slot)。
但是如果該程序的父程序已經先結束了,那麼該程序就不會變成殭屍程序。因為每個程序結束的時候,系統都會掃描當前系統中所執行的所有程序,看看有沒有哪個程序是剛剛結束的這個程序的子程序,如果是的話,就由Init程序來接管他,成為他的父程序,從而保證每個程序都會有一個父程序。而Init程序會自動wait其子程序,因此被Init接管的所有程序都不會變成殭屍程序。

二、 Linux下程序的運作方式
每個 Linux程序在程序表裡都有一個進入點(entry),核心程序執行該程序時使用到的一切資訊都儲存在進入點。當用 ps 命令察看系統中的程序資訊時,看到的就是程序表中的相關資料。當以fork()系統呼叫建立一個新的程序後,核心程序就會在程序表中給這個新程序分配一個進入點,然後將相關資訊儲存在該進入點所對應的程序表內。這些資訊中有一項是其父程序的識別碼。
子程序的結束和父程序的執行是一個非同步過程,即父程序永遠無法預測子程序到底什麼時候結束。那麼會不會因為父程序太忙來不及 wait 子程序,或者說不知道子程序什麼時候結束,而丟失子程序結束時的狀態資訊呢?
不會。因為 Linux提供了一種機制可以保證,只要父程序想知道子程序結束時的狀態資訊,就可以得到。這種機制就是:當子程序走完了自己的生命週期後,它會執行exit()系統呼叫,核心釋放該程序所有的資源,包括開啟的檔案,佔用的記憶體等。但是仍然為其保留一定的資訊(包括程序號the process ID,退出碼exit code,退出狀態the terminationstatus of the process,執行時間the amount of CPU time taken by the process等),這些資料會一直保留到系統將它傳遞給它的父程序為止,直到父程序通過wait / waitpid來取時才釋放。
也就是說,當一個程序死亡時,它並不是完全的消失了。程序終止,它不再執行,但是還有一些殘留的資料等待父程序收回。當父程序 fork() 一個子程序後,它必須用 wait() (或者 waitpid())等待子程序退出。正是這個 wait() 動作來讓子程序的殘留資料消失。
三、殭屍程序的危害
如果父程序不呼叫wait / waitpid的話,那麼保留的那段資訊就不會釋放,其程序號就會一直被佔用,但是系統的程序表容量是有限的,所能使用的程序號也是有限的,如果大量的產生殭屍程序,將因為沒有可用的程序號而導致系統不能產生新的程序。
所以,defunct程序不僅佔用系統的記憶體資源,影響系統的效能,而且如果其數目太多,還會導致系統癱瘓。而且,由於排程程式無法選中Defunct 程序,所以不能用kill命令刪除Defunct 程序,惟一的方法只有重啟系統。
四、如何殺死defunct程序
defunct程序是指出錯損壞的程序,父子程序之間不會再通訊。有時,它們會演變成“殭屍程序”,存留在你的系統中,直到系統重啟。可以嘗試 “kill -9” 命令來清除,但多數時候不管用。
為了殺死這些defunct程序,你有兩個選擇:
1.重啟你的計算機
2.繼續往下讀…
我們先看看系統中是否存在defunct程序:

$ ps -A|grep defunct

輸出

5259 ?        00:00:00 sd_cicero <defunct>
12214 pts/18   00:01:14 python <defunct>
16989 pts/18   00:04:43 python <defunct>
20610 pts/18   00:23:12 python <defunct>

看看這些程序的ID及其父程序ID:

$ ps -ef | grep defunct | more
UID PID PPID ...
====================================
====================================== yourname 4653 6128 0 17:07 pts/18 00:00:00 grep --color=auto defunct yourname 5259 5258 0 15:58 ? 00:00:00 [sd_cicero] <defunct> yourname 12214 12211 4 16:41 pts/18 00:01:14 [python] <defunct> yourname 16989 16986 20 16:45 pts/18 00:04:43 [python] <defunct> yourname 20610 18940 99 16:48 pts/18 00:23:12 [python] <defunct>

UID:使用者ID
PID:程序ID
PPID:父程序ID

如果你使用命令 “kill -9 12214” 嘗試殺死ID為12214的程序,可能會沒效果。
我們來試一下

$ kill -9 12214
$ ps -A|grep defunct

輸出

 5259 ?        00:00:00 sd_cicero <defunct>
12214 pts/18   00:01:14 python <defunct>
16989 pts/18   00:04:43 python <defunct>
20610 pts/18   00:23:12 python <defunct>

程序12214 仍然存才,說明用kill殺不掉它。

要想成功殺死該程序,需要對其父程序(ID為12211)執行kill命令($ kill -9 12211)。對所有這些程序的父程序ID應用kill命令,並驗證結果($ ps -A | grep defunct)。
我們來試一下

$ kill -9 12211
$ ps -A|grep defunct

輸出

5259 ?        00:00:00 sd_cicero <defunct>
16989 pts/18   00:04:43 python <defunct>
20610 pts/18   00:23:12 python <defunct>
[1]   Killed                  bash main.sh

程序12214消失,說明可以通過kill殭屍程序的父程序來殺死殭屍程序。

如果前一個命令顯示無結果,那麼搞定!否則,可能你需要重啟一下系統。