溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

第三章 九析帶你處理 zombie(defunct) 進(jìn)程

發(fā)布時(shí)間:2020-02-26 03:55:00 來(lái)源:網(wǎng)絡(luò) 閱讀:795 作者:九析 欄目:系統(tǒng)運(yùn)維

目錄

1 前言

2 僵尸進(jìn)程

????2.1 進(jìn)程簡(jiǎn)介

????2.2 僵尸進(jìn)程例子

????2.3 僵尸進(jìn)程危害

3 處理僵尸進(jìn)程

????3.1 kill 命令

????3.2 kill 父進(jìn)程

????3.3 reboot

????3.4 magic sysrq key 方法


1 前言

????????在 centos7 跑 Docker 和 k8s 時(shí),偶爾會(huì)出現(xiàn) systemctl 失效的情況,現(xiàn)象如下:

Failed to get properties...

????????查看系統(tǒng)進(jìn)程,發(fā)現(xiàn)僵尸進(jìn)程(zombie/defunct):

ps -ef | grep defunct


2 僵尸進(jìn)程

2.1 進(jìn)程簡(jiǎn)介

????????在 linux 中,父進(jìn)程通過(guò) fork 調(diào)用創(chuàng)建子進(jìn)程。

第三章 九析帶你處理 zombie(defunct) 進(jìn)程第三章 九析帶你處理 zombie(defunct) 進(jìn)程

????????子進(jìn)程執(zhí)行完畢之后,內(nèi)核會(huì)釋放該子進(jìn)程所占用的資源,包括打開(kāi)的文件,占用的內(nèi)存等,但仍然會(huì)在進(jìn)程表中保留一個(gè)槽位(slot)存放該子進(jìn)程的文件描述符(比如進(jìn)程PID、進(jìn)程退出狀態(tài)、進(jìn)程運(yùn)行時(shí)間等),直到父進(jìn)程發(fā)送 wait() 或 waitpid() 調(diào)用,內(nèi)核才會(huì)把子進(jìn)程文件描述符從進(jìn)程表中徹底清除。如果父進(jìn)程不調(diào)用 wait() 或 waitpid()對(duì)子進(jìn)程進(jìn)行清理,那子進(jìn)程將處于僵尸狀態(tài)。

????????但是如果父進(jìn)程先于子進(jìn)程結(jié)束的話,會(huì)導(dǎo)致子進(jìn)程變成僵尸進(jìn)程嗎?答案是不會(huì)。因?yàn)槊慨?dāng)進(jìn)程結(jié)束的時(shí)候,系統(tǒng)都會(huì)掃描當(dāng)前所有運(yùn)行的進(jìn)程,查找是否有這個(gè)結(jié)束進(jìn)程的子進(jìn)程,如果有,就由 init 進(jìn)程(或者 systemd 進(jìn)程)來(lái)接管子進(jìn)程,成為子進(jìn)程的新父進(jìn)程,并自動(dòng) wait 這個(gè)子進(jìn)程,確保以后該子進(jìn)程不會(huì)變成僵尸進(jìn)程。

2.2 僵尸進(jìn)程例子

????????下面展示一個(gè) c 語(yǔ)言編寫(xiě)的僵尸進(jìn)程樣例,樣例中主進(jìn)程并不會(huì) wait 子進(jìn)程,生成文件 zombie.c:

#include <unistd.h>

#include <stdio.h>

#include <stdlib.h>

int main(void) ?{

????int i = 60;

????pid_t pid = fork();


????if ( pid < 0 ) ?{

????????perror( "fork error." );

????????exit(1);

????}


????if ( pid == 0 ) {

????????printf( "This is the child process. My PID is: %d. My PPID is: %d\n", getpid(), getppid() );

????}


????if (pid > 0) ? ?{

????????printf( "This is the parent process. My PID is %d.\n", getpid() );

????????for( ; i > 0; i-- ) {

????????????sleep(1);

????????}

????}


????return 0;

}

????????編譯 zombie.c 并執(zhí)行 zombie:

yum install gcc

gcc zombie.c -o zombie

./ zombie

第三章 九析帶你處理 zombie(defunct) 進(jìn)程第三章 九析帶你處理 zombie(defunct) 進(jìn)程

????????上圖中主進(jìn)程 PID:11552,子進(jìn)程 PID:11553。執(zhí)行如下語(yǔ)句:發(fā)現(xiàn) PID 為 11553 的子進(jìn)程正好處于僵尸狀態(tài)(defunct),由程序可知,因?yàn)橹鬟M(jìn)程并沒(méi)有 wait 子進(jìn)程。

ps aux | grep -i defunct

第三章 九析帶你處理 zombie(defunct) 進(jìn)程第三章 九析帶你處理 zombie(defunct) 進(jìn)程? ? ? ? 分析一下 zombie.c,特別注意 fork() 調(diào)用,在 pid_t pid = fork() 語(yǔ)句之前,只有一個(gè)進(jìn)程,但是執(zhí)行到這條語(yǔ)句之后,就變成2個(gè)進(jìn)程了,這2個(gè)進(jìn)程幾乎完全相同,將要執(zhí)行的下一條語(yǔ)句都是 if ( pid < 0 )。

????????fork() 函數(shù)比較特殊,它被調(diào)用一次,卻能夠返回兩次結(jié)果,它的返回值也根據(jù)進(jìn)程的不同而不同:

1)在父進(jìn)程中,fork 返回新創(chuàng)建子進(jìn)程的 PID

2) 在子進(jìn)程中,fork 返回 0

3)如果出現(xiàn)錯(cuò)誤,則 fork 返回負(fù)值

2.3 僵尸進(jìn)程危害

????????如果父進(jìn)程沒(méi)有 wait 子進(jìn)程,子進(jìn)程將變成僵尸狀態(tài),處于僵尸狀態(tài)的進(jìn)程將保留進(jìn)程號(hào)(PID),眾所周知,操作系統(tǒng)對(duì)進(jìn)程號(hào)是有限制的,如果出現(xiàn)大量僵尸進(jìn)程占用進(jìn)程號(hào),系統(tǒng)有可能無(wú)法創(chuàng)建新的進(jìn)程。

3 處理僵尸進(jìn)程

????????一般情況下處于僵尸狀態(tài)的進(jìn)程很難殺掉,當(dāng)然你可以試著刪除:

3.1 kill 命令

kill -9 PID

3.2 kill 父進(jìn)程

kill -9 PPID

3.3 reboot

????????如果采用上面兩種方式依然殺不掉,那么只能通過(guò)重啟了。

reboot

????????如果重啟也不生效,可以需要加選項(xiàng) -nf

reboot -nf

3.4 magic sysrq key 方法

????????有時(shí)執(zhí)行 reboot 命令還是無(wú)法重啟,可以執(zhí)行 magic sysrq 方法來(lái)通過(guò)提供給用戶(hù)的 proc 接口直接向 kernel 發(fā)底層命令。

????????重啟命令如下:

echo 1 > /proc/sys/kernel/sysrq

echo b > /proc/sysrq-trigger

????????強(qiáng)制關(guān)機(jī)命令:

echo 1 > /proc/sys/kernel/sysrq

echo b > /proc/sysrq-trigger

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI