第三章 九析带你处理 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

相关文章
相关标签/搜索