1、什麼是defunct進程(殭屍進程)?
在 Linux 系統中,一個進程結束了,可是他的父進程沒有等待(調用wait / waitpid)他,那麼他將變成一個殭屍進程。當用ps命令觀察進程的執行狀態時,看到這些進程的狀態欄爲defunct。殭屍進程是一個早已死亡的進程,但在進程表(processs table)中仍佔了一個位置(slot)。
可是若是該進程的父進程已經先結束了,那麼該進程就不會變成殭屍進程。由於每一個進程結束的時候,系統都會掃描當前系統中所運行的全部進程,看看有沒有哪一個進程是剛剛結束的這個進程的子進程,若是是的話,就由Init進程來接管他,成爲他的父進程,從而保證每一個進程都會有一個父進程。而Init進程會自動wait其子進程,所以被Init接管的全部進程都不會變成殭屍進程。
2、 Linux下進程的運做方式
若是子進程先於父進程退出, 同時父進程又沒有調用wait/waitpid,則該子進程將成爲殭屍進程。若是該進程的父進程已經先結束了,那麼該進程就不會變成殭屍進程。由於每一個進程結束的時候,系統都會掃描當前系統中所運行的全部進程,看看有沒有哪一個 進程是剛剛結束的這個進程的子進程,若是是的話,就由Init進程來接管他,成爲他的父進程,從而保證每一個進程都會有一個父進程。而Init進程會自動 wait其子進程,所以被Init接管的全部進程都不會變成殭屍進程。
每一個 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() 動做來讓子進程的殘留數據消失。
3、殭屍進程的危害
若是父進程不調用wait / waitpid的話,那麼保留的那段信息就不會釋放,其進程號就會一直被佔用,可是系統的進程表容量是有限的,所能使用的進程號也是有限的,若是大量的產生殭屍進程,將由於沒有可用的進程號而致使系統不能產生新的進程。
因此,defunct進程不只佔用系統的內存資源,影響系統的性能,並且若是其數目太多,還會致使系統癱瘓。並且,因爲調度程序沒法選中Defunct 進程,因此不能用kill命令刪除Defunct 進程,唯一的方法只有重啓系統。
4、如何殺死defunct進程
defunct進程是指出錯損壞的進程,父子進程之間不會再通訊。有時,它們會演變成「殭屍進程」,存留在你的系統中,直到系統重啓。能夠嘗試 「kill -9」 命令來清除,但多數時候無論用。
爲了殺死這些defunct進程,你有兩個選擇:
1.重啓你的計算機
2.繼續往下讀…
咱們先看看系統中是否存在defunct進程:
$ ps -A|grep defunct
1
輸出
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>
1
2
3
4
看看這些進程的ID及其父進程ID:
$ ps -ef | grep defunct | more
1
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>
1
2
3
4
5
6
7
UID:用戶ID
PID:進程ID
PPID:父進程ID
若是你使用命令 「kill -9 12214」 嘗試殺死ID爲12214的進程,可能會沒效果。
咱們來試一下
$ kill -9 12214
$ ps -A|grep defunct
1
2
輸出
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>
1
2
3
4
進程12214 仍然存才,說明用kill殺不掉它。
要想成功殺死該進程,須要對其父進程(ID爲12211)執行kill命令($ kill -9 12211)。對全部這些進程的父進程ID應用kill命令,並驗證結果($ ps -A | grep defunct)。
咱們來試一下
$ kill -9 12211
$ ps -A|grep defunct
1
2
輸出
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 1 2 3 4 進程12214消失,說明能夠經過kill殭屍進程的父進程來殺死殭屍進程。