1. 程式人生 > 其它 >Linux下殭屍程序的處理與回收

Linux下殭屍程序的處理與回收

Linux下殭屍程序的處理與回收

一、殭屍程序是什麼?

殭屍程序就是已經結束的程序(幾乎不佔計算機資源),但是它並沒有從程序列表中刪除。殭屍程序太多會導致作業系統的程序數目過多,從而佔滿了OS的程序表。進而導致無法建立新程序,致使OS崩潰。
殭屍程序幾乎不佔資源,它沒有可執行程式碼,也不能被排程,但是它佔據著程序表中的一個位置,記載著該程序的PCB資訊。它需要等待他的父程序來終結它。一旦它的父程序是一個迴圈,不會結束(父程序不去呼叫wait函式或者waitpid函式)。那麼子程序將會一直保持殭屍狀態。那麼它將一直佔用程序號,系統就沒法回收利用。

二、殭屍程序是怎麼樣產生的?

每個Linux程序在程序表中都有一個進入點,核心執行該程序時,使用到的一切資訊都存入在程序點。我們可以使用ps命令來檢視程序狀態。當一個父程序以fork()系統呼叫建立一個新的子程序後,核心就會在程序表中給這個子程序分配一個進入點,然後將相關資訊儲存在該進入點所對應的程序表內。這些資訊中有一項是其父程序的識別碼。而當這個子程序結束的時候(呼叫exit命令結束),其實他並沒有真正的被銷燬,而是留下一個殭屍程序的。此時原來程序表中的資料會被該程序的退出碼(exit code)、執行時所用的CPU時間等資料所取代,這些資料會一直保留到系統將它傳遞給它的父程序為止。

三、殭屍程序如何避免?

  1. 可以在父程序中通過呼叫wait()和waitpid函式等待子程序結束,但是這會導致父程序掛起。
  2. 父程序不能掛起,父程序要做的工作很多,很忙。那麼可以使用signal函式為訊號SIGCHLD註冊處理函式。當子程序結束之後會發出SIGCHLD訊號,然後父程序會收到該訊號,可以在訊號處理函式中使用wait函式來回收子程序。
  3. 如果父程序不關心子程序什麼時候結束(比如fork後使用了execl函式啟動了另外一個可執行程式),那麼可以使用single(SIGCHLD,SIG_IGN)通知核心來回收子程序。
  4. fork兩次,首先父程序fork一個子程序,然後繼續工作,子程序fork一個孫子程序後退出,那麼孫子程序將會變成孤兒程序(因為他父親死了,這就是孤兒),從而被init程序接管。但是子程序的回收仍舊需要父程序來做,好處是不用使用wait()來掛起了,父程序可以忙自己的。

關鍵點:如果父程序有多個子程序,那麼當其中某一個子程序終止的時候,wait函式就會立即回收該子程序,並且返回。如果父程序關心子程序的終止狀態(正常結束還是異常結束),那麼需要傳遞一個引數來獲取狀態,如果不關心,可以傳遞引數NULL。

四、殭屍狀態是每個子程序必須經過的狀態嗎?

任何一個子程序(init除外)在exit()之後,並非馬上就消失掉,而是留下一個稱為殭屍程序(Zombie)的資料結構(它佔用一點記憶體 資源,也就是程序表裡還有一個記錄),等待父程序處理。這是每個子程序在結束時都要經過的階段。如果子程序在exit()之後,父程序沒有來得及處理,這時用ps命令就能看到子程序的狀態是“Z”。

五、殭屍程序如何檢視?

在linux中,利用命令ps,可以看到有標記為Z的程序就是殭屍程序。

ps -ef|grep defunc #可以找出殭屍程序.

可以用ps的-l選項,得到更詳細的程序資訊. F(Flag):一系列數字的和,表示程序的當前狀態。這些數字的含義為:

00:若單獨顯示,表示此程序已被終止。
01:程序是核心程序的一部分,常駐於系統主存。如:sched、 vhand 、bdflush 等。
02:Parent is tracing process.
04:Tracing parent’s signal has stopped the process; the parent is waiting ( ptrace(S)).
10:程序在優先順序低於或等於25時,進入休眠狀態,而且不能用訊號喚醒,例如在等待一個inode被建立時   
20:程序被裝入主存(primary memory)
40:程序被鎖在主存,在事務完成前不能被置換

S(state of the process )
O:程序正在處理器執行 
S:休眠狀態(sleeping)
R:等待執行(runable)   
I:空閒狀態(idle)
Z:殭屍狀態(zombie)   
T:跟蹤狀態(Traced)
B:程序正在等待更多的記憶體頁
C:cpu利用率的估算值(cpu usage)

六、殭屍程序如何清除?

  1. 改寫父程序,在子程序死後要為它收屍。具體做法是接管SIGCHLD訊號。子程序死後,會發送SIGCHLD訊號給父程序,父程序收到此信 號後,執行waitpid()函式為子程序收屍。這是基於這樣的原理:就算父程序沒有呼叫wait,核心也會向它傳送SIGCHLD訊息,儘管對的預設處 理是忽略,如果想響應這個訊息,可以設定一個處理函式。

SIGCHLD訊號:子程序結束時, 父程序會收到這個訊號。如果父程序沒有處理這個訊號,也沒有等待(wait)子程序,子程序雖然終止,但是還會在核心程序表中佔有表項,這時的子程序稱為 殭屍程序。這種情況我們應該避免(父程序或者忽略SIGCHILD訊號,或者捕捉它,或者wait它派生的子程序,或者父程序先終止,這時子程序的終止自 動由init程序來接管)。

  1. kill -18 PPID (PPID是其父程序)

這個訊號是告訴父程序,該子程序已經死亡了,請收回分配給他的資源。

SIGCONT也是一個有意思的訊號。如前所述,當程序停止的時候,這個訊號用來告訴程序恢復執行。該訊號的有趣的地方在於:它不能被忽略或阻塞,但可以被捕獲。預設行為是丟棄該訊號。

3. 終止父程序

如果方法2不能終止,可採用終止其父程序的方法(如果其父程序不需要的話)父程序死後,殭屍程序成為”孤兒程序”,過繼給1號程序init,init始終會負責清理殭屍程序.它產生的所有殭屍程序也跟著消失。

先看其父程序又無其他子程序,如果有,可能需要先kill其他子程序,也就是兄弟程序。方法是:

kill –15 PID1 PID2 (PID1,PID2是殭屍程序的父程序的其它子程序)。

然後再kill父程序:kill –15 PPID

這樣殭屍程序就可能被完全殺掉了。

參考連結:
https://blog.csdn.net/weixin_44489823/article/details/103260332
https://blog.csdn.net/zy010101/article/details/83715103