如何在 Linux 上殺死殭屍進程
已發表: 2022-01-29編寫不佳或性能不佳的程序可能會使殭屍進程潛伏在您的 Linux 計算機中。 了解殭屍是如何產生的,以及如何最終讓它們安息。
進程狀態如何在 Linux 上工作
當然,Linux 必須跟踪計算機上運行的所有應用程序和守護程序。 它執行此操作的方法之一是維護進程表。 這是內核內存中的結構列表。 每個進程在此列表中都有一個條目,其中包含有關它的一些信息。
每個進程表結構都沒有很多。 它們包含進程 ID、一些其他數據項和指向該進程的進程控制塊 (PCB) 的指針。
PCB 包含 Linux 需要為每個進程查找或設置的許多細節。 PCB 也會隨著進程的創建、處理時間和最終銷毀而更新。
Linux PCB 包含超過 95 個字段。 它被定義為一個名為task_struct.h
的結構,它有 700 多行。 PCB 包含以下類型的信息:
- 進程狀態:狀態如下所述。
- 進程號:它在操作系統中的唯一標識符。
- 程序計數器:當該進程下一次獲得對 CPU 的訪問權時,系統將使用此地址查找應執行的進程的下一條指令。
- Registers :此進程使用的 CPU 寄存器列表。 該列表可能包含累加器、索引寄存器和堆棧指針。
- 打開文件列表:與此進程關聯的文件。
- CPU 調度信息:用於確定分配給此進程的 CPU 處理時間的頻率和持續時間。 進程的優先級、調度隊列的指針和其他調度參數都必須記錄在 PCB 中。
- 內存管理信息:有關此進程正在使用的內存的詳細信息,例如進程內存的開始和結束地址,以及指向內存頁面的指針。
- I/O 狀態信息:進程使用的任何輸入或輸出設備。
“進程狀態”可以是以下任何一種:
- R:正在運行或可運行的進程。 運行意味著它正在接收 CPU 週期並執行。 可運行進程已準備好運行並等待 CPU 插槽。
- S:一個睡眠過程。 進程正在等待操作完成,例如輸入或輸出操作,或等待資源可用。
- D:進程處於不間斷睡眠狀態。 它正在使用阻塞系統調用,並且在系統調用完成之前無法繼續。 與“睡眠”狀態不同,處於此狀態的進程不會響應信號,直到系統調用完成並且執行返回到該進程。
- T:進程已終止(停止),因為它收到了
SIGSTOP
信號。 它只會響應SIGKILL
或SIGCONT
信號,它們分別殺死進程或指示它繼續。 當您從前台 (fg
) 切換到後台 (bg)
任務時,就會發生這種情況。 - Z:殭屍進程。 當一個過程完成時,它不會消失。 它釋放它正在使用的所有內存並將自己從內存中刪除,但它在進程表和 PCB 中的條目仍然存在。 它的狀態設置為
EXIT_ZOMBIE
,並且它的父進程被通知(通過SIGCHLD
信號)子進程已經完成。
在 Zombie 狀態下,父進程在創建子進程時調用wait()
系列函數之一。 然後它等待子進程中的狀態更改。 子進程是否被信號停止、繼續或終止? 它是否通過運行其代碼的自然完成而終止?
如果狀態變化意味著子進程已停止運行,則讀取其退出代碼。 然後,孩子的 PCB 被銷毀,它在進程表中的條目被刪除。 理想情況下,這一切都發生在眨眼之間,殭屍狀態的進程不會存在很長時間。
相關:如何在 Linux 上運行和控制後台進程
是什麼導致 Linux 上的殭屍進程?
創建子進程時,編寫不佳的父進程可能不會調用wait()
函數。 這意味著沒有任何東西在監視子進程中的狀態變化,並且SIGCHLD
信號將被忽略。 或者,也許另一個應用程序正在影響父進程的執行,這可能是由於糟糕的編程或惡意意圖。
但是,如果父進程沒有在子進程中監視狀態變化,則不會發生適當的系統內務處理。 當子進程終止時,PCB 和進程表中的條目不會被刪除。 這導致殭屍狀態永遠不會從 PCB 中移除。
殭屍確實會使用一些內存,但它們通常不會造成問題。 進程表中的條目很小,但是在它被釋放之前,進程 ID 不能被重用。 在 64 位操作系統上,這不太可能導致任何問題,因為 PCB 比進程表條目大得多。
可以想像,大量的殭屍可能會影響其他進程可用的內存量。 但是,如果您有這麼多殭屍,那麼您的父應用程序或操作系統錯誤就會出現嚴重問題。
如何刪除殭屍進程
你不能殺死一個殭屍進程,因為它已經死了。 它不會響應任何信號,因為它已從內存中刪除——沒有地方可以發送SIGKILL
信號。 您可以嘗試向父進程發送SIGCHLD
信號,但如果在子進程終止時它不起作用,那麼現在也不太可能起作用。
唯一可靠的解決方案是殺死父進程。 當它終止時,它的子進程被init
進程繼承,它是 Linux 系統中運行的第一個進程(它的進程 ID 為 1)。
init
進程定期執行必要的殭屍清理,因此要殺死它們,您只需殺死創建它們的進程即可。 top
命令是查看是否有任何殭屍的便捷方法。
鍵入以下內容:
最佳
這個系統有八個殭屍進程。 我們可以使用ps
命令列出這些並將其輸入egrep
。 同樣,殭屍進程的狀態標誌為“Z”,您通常還會看到“已失效”。
鍵入以下內容:
ps輔助| egrep "Z|已失效"
列出了殭屍進程。
這是發現殭屍進程 ID 的一種比在top
中來回滾動更簡潔的方法。 我們還看到一個名為“badprg”的應用程序催生了這些殭屍。
第一個殭屍進程的進程ID是7641,但是我們需要找到它的父進程的進程ID。 我們可以通過再次使用
來做到這一點。 我們將使用輸出選項 ( ps
-o
) 告訴ps
僅顯示父進程 ID,然後使用ppid=
標誌傳遞它。
我們要查找的進程將通過使用-p
(進程)選項來指示,然後傳入殭屍進程 ID。
因此,我們鍵入以下命令來查找進程7641的進程信息,但它只會報告父進程的ID:
ps -o ppid= -p 7641
我們被告知父進程 ID 是 7636。我們現在可以再次使用ps
交叉引用它。
我們看到這與之前的父進程的名稱相匹配。 要終止父進程,請在 kill 命令中使用 SIGKILL 選項,如下所示:
殺死-SIGKILL 7636
根據父進程的所有者,您可能還需要使用sudo
。
殭屍並不可怕……
……除非他們是一大群人。 一些無需擔心,簡單的重新啟動即可將它們清除。
但是,如果您注意到某個應用程序或進程總是產生殭屍程序,那麼您應該研究一下。 它很可能只是一個草率編寫的程序,在這種情況下,也許有一個更新版本可以在其子進程之後正確清理。