Linux孤兒進程和僵尸進程
在 Linux 系統中,父子進程關系的生命周期不同,導致會產生兩類特殊進程:孤兒進程和僵尸進程。這兩類進程在系統資源管理中起著重要作用。
1
孤兒進程
孤兒進程指的是父進程先于子進程結束,導致子進程失去父進程。為了避免這些進程無人管理,Linux 系統自動將孤兒進程的父進程重定向為 init 進程(PID 1),這使得孤兒進程得以繼續運行,并由 init 進程負責在子進程結束時回收其資源。
當父進程結束后,子進程可以通過 getppid() 系統調用獲取父進程的進程號。如果返回 1,則說明該子進程已經成為孤兒進程,因為它的父進程變為了 init。
孤兒進程的創建如下:
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void){ /* 創建子進程 */ switch (fork()) { case -1: perror("fork error"); exit(-1); case 0: /* 子進程 */ printf("子進程<%d>被創建, 父進程<%d>n", getpid(), getppid()); sleep(3); //休眠 3 秒等待父進程結束 printf("父進程<%d>n", getppid()); // 父進程變為 init,getppid() 返回 1 _exit(0); default: /* 父進程 */ break; } sleep(1); // 休眠 1 秒后父進程結束 printf("父進程結束!n"); exit(0);}
在這個代碼中,父進程在休眠 1 秒后結束,子進程在 3 秒后醒來并發現其父進程已經變為 init 進程,通過 getppid() 驗證這一點。這種情況下,子進程變成了孤兒進程。
2
僵尸進程
僵尸進程是指子進程先于父進程結束,且父進程沒有及時回收子進程資源的情況。當一個進程結束時,它的退出狀態仍然保留在系統進程表中,直到父進程調用 wait() 函數進行回收。如果父進程沒有調用 wait() 或其變體,子進程就會變成僵尸進程,占用系統資源。
如果系統中有大量僵尸進程,這些進程占用的資源將逐漸增加,最終可能耗盡進程表空間,導致無法創建新的進程。因此,及時調用 wait() 函數回收子進程非常重要。
僵尸進程的創建如下:
#include <stdio.h>#include <stdlib.h>#include <unistd.h> int main(void){ /* 創建子進程 */ switch (fork()) { case -1: perror("fork error"); exit(-1); case 0: /* 子進程 */ printf("子進程<%d>被創建n", getpid()); sleep(1); printf("子進程結束n"); _exit(0); // 子進程結束 default: /* 父進程 */ break; } for ( ; ; ) { // 父進程沒有調用 wait(),導致子進程變為僵尸進程 sleep(1); } exit(0);}
在這個代碼中,子進程在 1 秒后結束,而父進程沒有調用 wait() 函數,這導致子進程進入僵尸狀態。可以通過 ps -aux 命令查看僵尸進程,其狀態標記為 Z (zombie)。
僵尸進程的清理方法:
父進程調用 wait():當父進程調用 wait() 函數后,僵尸進程將被內核徹底移除。
殺死父進程:如果父進程沒有調用 wait(),我們可以通過殺死父進程,令 init 進程接管僵尸進程,從而清理它。
通過合理的進程管理,例如及時調用 wait(),可以有效防止僵尸進程的累積并保持系統的正常運行。
*博客內容為網友個人發布,僅代表博主個人觀點,如有侵權請聯系工作人員刪除。