Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 殭屍進程原理、危害與清理實戰

編輯:Linux 教學

進程呼叫 exit() 後並不會立即消失,而是留下一個「殭屍進程」資料結構,佔據進程表項目,儲存退出碼、CPU 時間、頁錯誤次數等資訊,等待父進程呼叫 wait() 或 waitpid() 收集。若父進程疏忽未收集,殭屍將長期佔用 PID,嚴重時導致無法建立新進程。本文深入解析殭屍生命週期、示範 C 程式製造殭屍,並說明正確清理姿勢。

殭屍進程為何存在?

  • 保留退出資訊:父進程需要知道子進程是正常結束、被訊號殺死、還是核心傾印,以及資源使用統計。
  • 非同步收集:父進程可能忙於其他工作,無法立即處理 SIGCHLD;核心將子進程標記為 Z(Zombie),保留最小資料結構等待父進程。
  • 不可被 kill:kill -9 對殭屍無效,因為它已非執行實體;唯有父進程 wait 或父進程結束(由 init 繼承收集)才能徹底釋放。

實作示範:製造殭屍

/* zombie.c */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(1);
    } else if (pid == 0) {        /* 子進程:立即結束 */
        printf("Child %d exiting\n", getpid());
        exit(0);
    } else {                      /* 父進程:睡眠 60 秒不收集 */
        printf("Parent %d sleeping, child %d becomes zombie\n", getpid(), pid);
        sleep(60);
        wait(NULL);               /* 最後收集 */
        printf("Parent reaped child\n");
    }
    return 0;
}

編譯與觀察

$ gcc zombie.c -o zombie
$ ./zombie &
[1] 1217
$ ps -ax | grep -E 'zombie|Z'
 1217 pts/0 S  0:00 ./zombie
 1218 pts/0 Z  0:00 [zombie] <-- 狀態 Z 即殭屍
 1578 pts/0 R  0:00 ps -ax

正確清理姿勢

方法一:父進程主動 wait

/* 在父進程適當位置呼叫 */
while (waitpid(-1, NULL, WNOHANG) > 0) { /* 清理所有已結束子進程 */ }
  • wait():阻塞直到任一子進程結束。
  • waitpid(pid, &status, WNOHANG):非阻塞檢查特定 PID;WNOHANG 讓呼叫立即返回,適合在事件迴圈中定期清理。

方法二:忽略 SIGCHLD(自動清理)

signal(SIGCHLD, SIG_IGN);  /* 讓核心自動回收,適用於不需要知道退出碼的簡單服務 */

Linux 核心見 SIG_IGN 會自動釋放子進程資源,無殭屍產生。

方法三:雙重 Fork 技巧(守護進程常用)

if (fork() == 0) {          /* 第一層子進程 */
    if (fork() == 0) {      /* 第二層孫進程:真正工作 */
        do_work();
        exit(0);
    }
    exit(0);                /* 第一層子進程立即結束 */
}
waitpid(first_child, NULL, 0); /* 父進程等待第一層,孤兒孫進程由 init 收養 */

常見問題與對策

現象原因解決
大量 <defunct> 進程父進程未呼叫 wait修正父進程代碼加入 waitpid 迴圈
無法建立新進程(PID 用盡)殭屍佔滿 PID 空間重啟父進程或機器;長期修正代碼
kill -9 無效殭屍非執行實體只能等待父進程 wait 或父進程結束

排查工具

  • ps -eo pid,ppid,stat,cmd | grep Z:列出所有殭屍及其父進程 PID。
  • top / htop:Tasks 列會顯示 zombie 計數。
  • cat /proc/PID/status | grep State:確認單一進程狀態。
最佳實踐:所有建立子進程的程式(特別是長期運行的服務),務必在適當位置設置 SIGCHLD 處理器並呼叫 waitpid(-1, &status, WNOHANG),或直接 signal(SIGCHLD, SIG_IGN)。這是 Unix/Linux 系統程式設計的基本衛生習慣。
Copyright © Windows教程網 All Rights Reserved