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

目錄linux

1 前言centos

2 殭屍進程ide

    2.1 進程簡介函數

    2.2 殭屍進程例子centos7

    2.3 殭屍進程危害spa

3 處理殭屍進程操作系統

    3.1 kill 命令3d

    3.2 kill 父進程blog

    3.3 reboot接口

    3.4 magic sysrq key 方法


1 前言

        在 centos7 跑 Docker 和 k8s 時,偶爾會出現 systemctl 失效的狀況,現象以下:

Failed to get properties...

        查看系統進程,發現殭屍進程(zombie/defunct):

ps -ef | grep defunct


2 殭屍進程

2.1 進程簡介

        在 linux 中,父進程經過 fork 調用建立子進程。

spacer.gifclipboard.png

        子進程執行完畢以後,內核會釋放該子進程所佔用的資源,包括打開的文件,佔用的內存等,但仍然會在進程表中保留一個槽位(slot)存放該子進程的文件描述符(好比進程PID、進程退出狀態、進程運行時間等),直到父進程發送 wait() 或 waitpid() 調用,內核纔會把子進程文件描述符從進程表中完全清除。若是父進程不調用 wait() 或 waitpid()對子進程進行清理,那子進程將處於殭屍狀態。

        可是若是父進程先於子進程結束的話,會致使子進程變成殭屍進程嗎?答案是不會。由於每當進程結束的時候,系統都會掃描當前全部運行的進程,查找是否有這個結束進程的子進程,若是有,就由 init 進程(或者 systemd 進程)來接管子進程,成爲子進程的新父進程,並自動 wait 這個子進程,確保之後該子進程不會變成殭屍進程。

2.2 殭屍進程例子

        下面展現一個 c 語言編寫的殭屍進程樣例,樣例中主進程並不會 wait 子進程,生成文件 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 並執行 zombie:

yum install gcc

gcc zombie.c -o zombie

./ zombie

spacer.gifclipboard2.png

        上圖中主進程 PID:11552,子進程 PID:11553。執行以下語句:發現 PID 爲 11553 的子進程正好處於殭屍狀態(defunct),由程序可知,由於主進程並無 wait 子進程。

ps aux | grep -i defunct

spacer.gifclipboard3.png        分析一下 zombie.c,特別注意 fork() 調用,在 pid_t pid = fork() 語句以前,只有一個進程,可是執行到這條語句以後,就變成2個進程了,這2個進程幾乎徹底相同,將要執行的下一條語句都是 if ( pid < 0 )。

        fork() 函數比較特殊,它被調用一次,卻可以返回兩次結果,它的返回值也根據進程的不一樣而不一樣:

1)在父進程中,fork 返回新建立子進程的 PID

2) 在子進程中,fork 返回 0

3)若是出現錯誤,則 fork 返回負值

2.3 殭屍進程危害

        若是父進程沒有 wait 子進程,子進程將變成殭屍狀態,處於殭屍狀態的進程將保留進程號(PID),衆所周知,操做系統對進程號是有限制的,若是出現大量殭屍進程佔用進程號,系統有可能沒法建立新的進程。

3 處理殭屍進程

        通常狀況下處於殭屍狀態的進程很難殺掉,固然你能夠試着刪除:

3.1 kill 命令

kill -9 PID

3.2 kill 父進程

kill -9 PPID

3.3 reboot

        若是採用上面兩種方式依然殺不掉,那麼只能經過重啓了。

reboot

        若是重啓也不生效,能夠須要加選項 -nf

reboot -nf

3.4 magic sysrq key 方法

        有時執行 reboot 命令仍是沒法重啓,能夠執行 magic sysrq 方法來經過提供給用戶的 proc 接口直接向 kernel 發底層命令。

        重啓命令以下:

echo 1 > /proc/sys/kernel/sysrq

echo b > /proc/sysrq-trigger

        強制關機命令:

echo 1 > /proc/sys/kernel/sysrq

echo b > /proc/sysrq-trigger

相關文章
相關標籤/搜索