僵屍進程(Zombie Process)是已終止但尚未被父進程回收的進程殘留結構,大量堆積會耗盡 PID 資源導致無法建立新進程。
exit() 結束,釋放記憶體、檔案描述符等資源task_struct,進入 EXIT_ZOMBIE 狀態wait()/waitpid() 讀取退出碼,核心才釋放結構SIGCHLD,子進程將長期滯留為僵屍/proc/sys/kernel/pid_max)ps/top 顯示 Z 狀態干擾監控ps aux | awk '$8 ~ /Z/ {print $2, $11}' # 列出僵屍 PID 與命令
ps -eo pid,ppid,stat,cmd | grep '^.* Z'
cat /proc/<PID>/status | grep State # 確認 Z (zombie)
// 阻塞等待任一子進程
pid_t pid = wait(&status);
// 非阻塞輪詢
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { /* 處理 */ }
void sigchld_handler(int sig) {
int saved_errno = errno;
while (waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
signal(SIGCHLD, sigchld_handler); // 或 sigaction 更安全
signal(SIGCHLD, SIG_IGN); // Linux 核心 2.6+ 支援
// 或更嚴謹的 SA_NOCLDWAIT
struct sigaction sa = { .sa_handler = SIG_IGN, .sa_flags = SA_NOCLDWAIT };
sigaction(SIGCHLD, &sa, NULL);
pid_t pid = fork();
if (pid == 0) { // 子進程
pid_t pid2 = fork();
if (pid2 == 0) { // 孫進程執行實際工作
do_work();
exit(0);
}
exit(0); // 子進程立即結束
}
waitpid(pid, NULL, 0); // 父進程回收子進程
// 孫進程成為孤兒,由 init (PID 1) 收養並自動回收
預防勝於治療:編寫網路服務、多進程應用時,務必正確處理 SIGCHLD 或採用 Double-fork,從架構層面杜絕僵屍產生。