僵尸進程是指它的父進程已經退出(父進程沒有等待(調用wait/waitpid)它),而該進程dead之后沒有進程接受,就成為僵尸進程,也就是(zombie)進程。
一個進程在調用了exit命令之后結束了自己的生命時候,你以為是真的被徹底銷毀了嗎?其實不然,它只是變成了我們稱之為“僵尸進程”狀態。在用戶態程序調用系統調用exit時,也僅僅限于將一個正常的進程變成了一個僵尸進程,并沒有完全的銷毀。看下圖所示:
在linux中,進程的狀態有5種,其中僵尸進程狀態是一種比較奇葩的存在方式,它放棄了幾乎所有的內存地址空間,也沒有任何的可執行的代碼,也不可能被調度器再次調度,它僅僅是在進程列表中保留一個位置,在這個位置中記載了該進程的狀態。而它也只是靜靜的等待著其他進程(父進程后者init進程)為他收尸。
假如它的父進程沒有安裝SIGCHLD信號處理函數來處理子進程(也即使wait或者waitpid等待兒子結束),又沒有顯示忽略該信號,那子進程就會一直保持僵尸狀態。只有在父進程結束之后,才由init進程接管子進程,為他收尸(好凄慘啊),這個時候才能說子進程才真正的消失在Linux內核中。
又假如父進程是個無限循環的進程,那么子進程就會一直保持僵尸狀態。這就能解釋為什么系統運行久了,會出現大量的僵尸狀態的進程。出現僵尸狀態進程的數量少,是沒有任何問題的,一旦出現巨量情況,就會導致PID用完,而給新的進程分配PID,當然也就會創建新進程失敗。
為什么要有僵尸狀態呢?
主要是因為父進程可能要取得子進程的退出狀態等信息。僵尸狀態是每一個進程必須要經過的過程(除init進程之外)。
那怎么避免呢?
當前能給出四種方案,分別是:
- 父進程通過wait或waitpid函數等待子進程結束,這樣有個問題,就是會導致父進程掛起。
- 如果父進程很忙,可以采用異步的方式,注冊SIGCHLD信號處理函數,在處理函數中wait回收子進程。
- 如果父進程對子進程生死不感興趣,也可以通過signal(SIGCHLD,SIG_IGN)告知內核,忽視掉該信號。當然子進程結束后,內核會幫助回收。
- 還可以用一些技巧,比如fork兩次。子進程退出,孫進程就由init進程接管回收了。這個方法的代碼網絡上多如牛毛。自信百度查看。
?
如何查看僵尸進程呢?
在Linux中,可以使用ps命令,ps 命令就是最根本相應情況下也是相當強大地進程查看命令.運用該命令可以確定有哪些進程正在運行和運行地狀態、 進程 是否結束、進程有沒有僵死、哪些進程占用了過多地資源等等.總之大部分信息均為可以通過執行該命令得到地.
標記“Z”的進程就是僵尸進程了。
ps -ef
可以用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)
另外使用top命令查看時有一欄為S,如果狀態為Z說明它就是僵尸進程。