如何找到并殺掉 Linux 系統(tǒng)中的僵尸進(jìn)程
這是一個(gè)關(guān)于如何尋找 Linux 系統(tǒng)僵尸進(jìn)程并殺死它們的小知識(shí)。你也可以從中了解到關(guān)于進(jìn)程和僵尸進(jìn)程的一些知識(shí)。
在了解僵尸進(jìn)程之前,讓我們來(lái)復(fù)習(xí)一下什么是 Linux 進(jìn)程。
簡(jiǎn)而言之,進(jìn)程 是一個(gè)程序的運(yùn)行實(shí)例。它可能運(yùn)行在前端(比如有交互的進(jìn)程),也可能運(yùn)行在后端(比如無(wú)交互或自動(dòng)運(yùn)行的進(jìn)程)。它可能是一個(gè)父進(jìn)程(運(yùn)行期間創(chuàng)建了其他進(jìn)程),也可能是一個(gè)子進(jìn)程(由其他進(jìn)程所創(chuàng)建)。
在 Linux 系統(tǒng)中,除 PID 為 0 的第一個(gè) init
進(jìn)程(或 systemd
)外,其余進(jìn)程都有父進(jìn)程。進(jìn)程也可以擁有自己的子進(jìn)程。
不相信?可以試試在終端中使用 pstree
命令查看進(jìn)程的樹(shù)型結(jié)構(gòu),你能看到系統(tǒng)各個(gè)進(jìn)程的“家族樹(shù)”。
Linux系統(tǒng)里的僵尸進(jìn)程是什么?
子進(jìn)程死亡后,它的父進(jìn)程會(huì)接收到通知去執(zhí)行一些清理操作,如釋放內(nèi)存之類(lèi)。然而,若父進(jìn)程并未察覺(jué)到子進(jìn)程死亡,子進(jìn)程就會(huì)進(jìn)入到“僵尸”狀態(tài)。從父進(jìn)程角度看,子進(jìn)程仍然存在,即使子進(jìn)程實(shí)際上已經(jīng)死亡。這就是“僵尸進(jìn)程”(也被稱(chēng)為“已消失進(jìn)程”)是如何產(chǎn)生并存在于系統(tǒng)中的。
這里有一個(gè)來(lái)自 Turnoff.us 的關(guān)于僵尸進(jìn)程的非常有趣的看法:
Image credit: Turnoff.us
你真的需要關(guān)心僵尸進(jìn)程嗎?
重點(diǎn)要說(shuō)的是,僵尸進(jìn)程并沒(méi)有像它的名稱(chēng)那樣看起來(lái)可怕。
但如果系統(tǒng)的內(nèi)存已經(jīng)所剩不多或者有太多的僵尸進(jìn)程在吃掉內(nèi)存,問(wèn)題會(huì)變得糟糕。同樣,大部分 Linux 系統(tǒng)進(jìn)程最大 PID 設(shè)置為 32768,如果過(guò)多僵尸進(jìn)程導(dǎo)致其他重要任務(wù)沒(méi)有 PID 可用,你的系統(tǒng)會(huì)發(fā)生崩潰。
這是真實(shí)可能發(fā)生的,它有一定的概率,特別當(dāng)存在一個(gè)編碼糟糕的程序開(kāi)始大量產(chǎn)生僵尸進(jìn)程的時(shí)候。
在這種情況下,找到并殺死僵尸進(jìn)程是一個(gè)明智的做法。
如何找到僵尸進(jìn)程
Linux 系統(tǒng)中的進(jìn)程可能處于如下?tīng)顟B(tài)中的一種:
D
= 不可中斷的休眠I
= 空閑R
= 運(yùn)行中S
= 休眠T
= 被調(diào)度信號(hào)終止t
= 被調(diào)試器終止Z
= 僵尸狀態(tài)
那如何查看進(jìn)程和它的當(dāng)前狀態(tài)呢?一個(gè)簡(jiǎn)單的方法是在終端中使用 top 命令。
Top command show processes and their status
正如你在上面截圖中看到的,截圖中共有 250 個(gè)任務(wù)(進(jìn)程),其中 1 個(gè)處在 “運(yùn)行中” 狀態(tài),248 個(gè)進(jìn)程處于 “休眠” 狀態(tài),還有一個(gè)處于 “僵尸” 狀態(tài)。
現(xiàn)在問(wèn)題進(jìn)入下一步,如何殺死 “僵尸” 進(jìn)程?
如何找到并殺死一個(gè)僵尸進(jìn)程?僵尸進(jìn)程能被殺死嗎?
僵尸進(jìn)程已經(jīng)死了,要如何才能殺死一個(gè)已經(jīng)死亡的進(jìn)程呢?
在僵尸電影中,你可以射擊僵尸的頭部或燒掉它們,但在這里是行不通的。你可以一把火燒了系統(tǒng)來(lái)殺死僵尸進(jìn)程,但這并不是一個(gè)可行的方案。
一些人建議發(fā)送 SIGCHLD
給父進(jìn)程,但這個(gè)信號(hào)很可能會(huì)被忽略。還有一個(gè)方法是殺死父進(jìn)程來(lái)殺死僵尸進(jìn)程,這聽(tīng)起來(lái)很野蠻,但它卻是唯一能確保殺死僵尸進(jìn)程的方法。
首先,通過(guò)在終端中 使用 ps 命令 我們列舉僵尸進(jìn)程,得到它們的進(jìn)程 ID:
ps ux | awk '{if($8=="Z+") print}'
ps ux
命令輸出的第 8 列顯示了進(jìn)程狀態(tài)。上述命令只會(huì)打印所有處在 Z+ 狀態(tài)(表示僵尸狀態(tài))的進(jìn)程。
確認(rèn)了進(jìn)程 ID 后,我們可以得到它的父進(jìn)程 ID:
ps -o ppid= -p <child_id>
你也可以將上述兩個(gè)命令結(jié)合在一起,直接得到僵尸進(jìn)程的 PID 及其父進(jìn)程的 PID:
ps -A -ostat,pid,ppid | grep -e '[zZ]'
現(xiàn)在你得到了父進(jìn)程 ID,使用命令行和得到的 ID 號(hào) 終于可以殺死進(jìn)程了:
kill -9 <parent_process_ID>
Killing parent process
再次運(yùn)行 ps
命令或 top
命令,你可以驗(yàn)證僵尸進(jìn)程是否已經(jīng)被殺死。
恭喜!現(xiàn)在你知道怎么清理僵尸進(jìn)程了。