文章随机晒最新文章关照最多的

jiayi Rss

Linux 僵死进程(zombie)

| Posted in APUE |

11

Linux 中有一种“死不瞑目”的进程,叫僵死进程(zombie)。一句话定义僵死进程:In UNIX System terminology, a process that has terminated, but whose parent has not yet waited for it, is called a zombie. 这些进程可以通过 ps 命令查看:ps -el ,带有 Z 标记的为僵死进程。也可以 ps -ef | grep defunc

一个进程exit()后,内核会将它的exit status 转换为 termination status,并由内核记录。可见这个结束的进程并没有真正的被销毁,虽然它已经不占用任何内存和cpu资源,没有任何可执行代码,也不能被调度,但却残留在进程列表里,一旦这种进程过多,系统性能肯定受其影响。这就需要它的父进程为它“收尸”,来获取已经terminate的子进程的终止状态(通常wait()waitpid() 来完成)。如果父进程在子进程之前退出,子进程会变成僵死进程了么…?不会的,这些子进程会被1号进程init 收留,并由1号进程init为它们”收尸“。

为了更好的说明僵死进程这个东东,我们人为的制造一个。。。 

C code


#include<stdio.h>

#include<stdlib.h>
#include<errno.h>
#include<unistd.h>
#include<sys/stat.h>
#include <sys/wait.h>

int
main(void)
{
    pid_t pid;
    pid_t pid1;
    pid_t wait_pid;

    printf("The parent’s pid is %dn",getpid());
    if ((pid = fork()) < 0)  
    {  
        perror("fork error");
    }  
    else if (pid == 0)  
    {       /* first child */
        if ((pid = fork()) < 0)
            perror("fork error");
        else if (pid > 0)
        {
            printf("First child of the parent is %dn",getpid());
            exit(0);
        }

        sleep(1);
        printf("First child’s child awaked…n");
        printf("pid = %d, parent pid = %dn",getpid(), getppid());
        exit(0);
    }
    else /*The parent process*/
    {
        if((pid1=fork())<0)
            perror("Fork");
        else if(pid1==0)
        {
            printf("Second child of the parent is %dn",getpid());
            exit(0);
        }
    }

    sleep(3);
    printf("parent awaked…n");
    if ((wait_pid=waitpid(pid1, NULL, 0)) == pid1)  // wait for second child
    {
        printf("seconde child has been waited: value of wait_pid is %dn",wait_pid);
    }
    while(1)
        ;

    exit(0);
}

编译运行得到

jiayi:/home/jiayi/apue # ./waitpid
The parent’s pid is 20334
Second child of the parent is 20337
First child of the parent is 20335
First child’s child awaked…
pid = 20336, parent pid = 1
parent awaked…
seconde child has been waited: value of wait_pid is 20337

另一个终端运行 ps -ef 得到最后三行

root     20334  9667 90 21:55 pts/7    00:37:28 ./waitpid
root     20335 20334  0 21:55 pts/7    00:00:00 [waitpid] <defunct>
jiayi  20459 20152  0 22:37 pts/2    00:00:00 ps -ef

一句一句分析程序打印的结果
此程序的进程号为20334;父进程第二个子进程的进程号为20337;父进程第一个子进程的进程号为20335(从这两个进程的打印顺序可以看出,两个进程存在竞争);20335的子进程 20336在睡觉,醒来后发现它的父进程变成了1,这是因为2033520336结束之前已经结束,20336进程被1init收留;父进程在睡觉,醒来后通过waitpid()成功获取第二个子进程20337的终止信息,然后很没素质的作起了无限循环…

至此,父进程在循环,两个子进程以及第一个子进程的子进程都已终止。其中第二个子进程 20337 被收尸,彻底销毁;子进程的子进程被1号init 收尸,也完全销毁;第一个子进程呢…? 看一下 ps 命令的结果,同样一句一句看:
20334号父进程在运行,因为它在作无限循环…;20335号子进程由defunct 标记,说明是一个僵死进程…… 另外两个子进程没有被发现,因为它们已经彻底解脱…

实验还没有结束,这时我们摁下 ctrl + c 将无限循环的父进程 20334 干掉,重新 ps -ef ,那个僵死进程也不见了。。。这是因为父进程 20334 被干掉后,僵死进程被1init ”收尸“,从而彻底解脱。。。

额,弄一个僵死进程出来还挺不容易的。。。

Comments (11)

厄,写个最基本的让偶能看得懂的吧~~

听起来很可怕呵呵

不错,虽然还是不太了解~~

Write a comment

You must be logged in to post a comment.