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