一、什麼是defunct程序(僵屍程序)?
在 Linux 系統中,一個程序結束了,但是他的父程序沒有等待(調用wait / waitpid)他,那麼他将變成一個僵屍程序。當用ps指令觀察程序的執行狀态時,看到這些程序的狀态欄為defunct。僵屍程序是一個早已死亡的程序,但在程序表(processs table)中仍占了一個位置(slot)。
但是如果該程序的父程序已經先結束了,那麼該程序就不會變成僵屍程序。因為每個程序結束的時候,系統都會掃描目前系統中所運作的所有程序,看看有沒有哪個程序是剛剛結束的這個程序的子程序,如果是的話,就由Init程序來接管他,成為他的父程序,進而保證每個程序都會有一個父程序。而Init程序會自動wait其子程序,是以被Init接管的所有程序都不會變成僵屍程序。
二、 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() 動作來讓子程序的殘留資料消失。
三、僵屍程序的危害
如果父程序不調用wait / waitpid的話,那麼保留的那段資訊就不會釋放,其程序号就會一直被占用,但是系統的程序表容量是有限的,所能使用的程序号也是有限的,如果大量的産生僵屍程序,将因為沒有可用的程序号而導緻系統不能産生新的程序。
是以,defunct程序不僅占用系統的記憶體資源,影響系統的性能,而且如果其數目太多,還會導緻系統癱瘓。而且,由于排程程式無法選中Defunct 程序,是以不能用kill指令删除Defunct 程序,惟一的方法隻有重新開機系統。
四、如何殺死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>
2
3
4
看看這些程序的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>
5
6
7
UID:使用者ID
PID:程序ID
PPID:父程序ID
如果你使用指令 “kill -9 12214” 嘗試殺死ID為12214的程序,可能會沒效果。
我們來試一下
$ kill -9 12214
5259 ? 00:00:00 sd_cicero <defunct>
程序12214 仍然存才,說明用kill殺不掉它。
要想成功殺死該程序,需要對其父程序(ID為12211)執行kill指令($ kill -9 12211)。對所有這些程序的父程序ID應用kill指令,并驗證結果($ ps -A | grep defunct)。
$ kill -9 12211
[1] Killed bash main.sh
程序12214消失,說明可以通過kill僵屍程序的父程序來殺死僵屍程序。
如果前一個指令顯示無結果,那麼搞定!否則,可能你需要重新開機一下系統。
---------------------
作者:DarrenXf
來源:CSDN
原文:https://blog.csdn.net/DarrenXf/article/details/82970809
版權聲明:本文為部落客原創文章,轉載請附上博文連結!