僵屍進程產生原因和解決方法


在linux系統中,當用ps命令觀察進程的執行狀態時,經常看到某些進程的狀態欄為defunct,這就是所謂的“僵屍”進程。“僵屍”進程是一個早已死亡的進程,但在進程表(processs table)中仍占了一個位置(slot)。由於進程表的容量是有限的,所以,defunct進程不僅占用系統的內存資源,影響系統的性能,而且如果其數目太多,還會導致系統癱瘓。

 

 我們可以使用top命令直接查看僵屍進程個數:

 

 

一、僵屍進程的產生原因

我們知道,每個進程在進程表里都有一個進入點(entry),核心程序執行該進程時使用到的一切信息都存儲在進入點。當用ps命令察看系統中的進程信息時,看到的就是進程表中的相關數據。

所以,當一個父進程以fork()系統調用建立一個新的子進程后,核心進程就會在進程表中給這個子進程分配一個進入點,然后將相關信息存儲在該進入點所對應的進程表內。這些信息中有一項是其父進程的識別碼。

而當這個子進程結束的時候(比如調用exit命令結束),其實他並沒有真正的被銷毀,而是留下一個稱為僵屍進程(Zombie)的數據結構(系統調用exit的作用是使進程退出,但是也僅僅限於一個正常的進程變成了一個僵屍進程,並不能完全將其銷毀)。

此時原來進程表中的數據會被該進程的退出碼(exit code)、執行時所用的CPU時間等數據所取代,這些數據會一直保留到系統將它傳遞給它的父進程為止。由此可見,defunct進程的出現時間是在子進程終止后,但是父進程尚未讀取這些數據之前。

此時,該僵屍子進程已經放棄了幾乎所有的內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態信息供其他進程收集,除此之外,僵屍進程不再占有任何存儲空間。他需要他的父進程來為他收屍,如果他的父進程沒有安裝SIGCHLD信號處理函數調用wait 或 waitpid() 等待子進程結束,也沒有顯式忽略該信號,那么它就一直保持僵屍狀態,如果這時候父進程結束了,那么init進程會自動接手這個子進程,為他收屍,他還是能被清除掉的。但是如果父進程是一個循環,不會結束,那么子進程就會一直保持僵屍狀態,這就是系統中為什么有時候會有很多的僵屍進程。

簡單解釋就是:

當你運行一個程序時,它會產生一個父進程以及很多子進程。 所有這些子進程都會消耗內核分配給它們的內存和 CPU 資源。
這些子進程完成執行后會發送一個 Exit 信號然后死掉。這個 Exit 信號需要被父進程所讀取。父進程需要隨后調用 wait 命令來讀取子進程的退出狀態,並將子進程從進程表中移除。
若父進程正確第讀取了子進程的 Exit 信號,則子進程會從進程表中刪掉。
但若父進程未能讀取到子進程的 Exit 信號,則這個子進程雖然完成執行處於死亡的狀態,但也不會從進程表中刪掉。

二、僵屍進程對系統有害嗎?

不會。由於僵屍進程並不做任何事情, 不會使用任何資源也不會影響其它進程, 因此存在僵屍進程也沒什么壞處。

不過由於進程表中的退出狀態以及其它一些進程信息也是存儲在內存中的,因此存在太多僵屍進程有時也會是一些問題。

三、如何殺死僵屍進程

如上可知,僵屍進程一旦出現之后,很難自己消亡,會一直存在下去,直至系統重啟。雖然僵屍進程幾乎不占系統資源,但是,這樣下去,數量太多了之后,終究會給系統帶來其他的影響。因此,如果一旦見到僵屍進程,我們就要將其殺掉。如何殺掉僵屍進程呢?

有同學可能會說,很簡單嘛,直接使用kill命令就好啊。或者,實在不行,加一個-9的后綴(kill -9),肯定殺掉!

請注意:defunct狀態下的僵屍進程是不能直接使用kill -9命令殺掉的,否則就不叫僵屍進程了。那么,該如何殺呢?

方法:

  1. 重啟服務器電腦,這個是最簡單,最易用的方法,但是如果你服務器電腦上運行有其他的程序,那么這個方法,代價很大。所以,盡量使用下面一種方法。
  2. 找到該defunct僵屍進程的父進程,將該進程的父進程殺掉,則此defunct進程將自動消失。

問題又來了,如何找到defunct僵屍進程的父進程呢?

ps -ef | grep defunct_process_pid

111

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM