Linux 允许进程查询内核以获得其父进程的 PID,或者其任何子进程的执行状态。例如,进程可以创建一个子进程来执行特定的任务,然后调用诸如 wait() 这样的一些库函数检查子进程是否终止。如果子进程已经终止,那么,它的终止代号将告诉父进程这个任务是否已成功地完成。
为了遵循这些设计原则,不允许 Linux 内核在进程一终止后就丢弃包含在进程描述符字段中的数据。只有父进程发出了与被终止的进程相关的 wait() 类系统调用之后,才允许这样做。这就是引入僵死状态的原因:尽管从技术上来说进程已死,但必须保存它的描述符,直到父进程得到通知。
如果一个进程已经终止,但是它的父进程尚未调用 wait() 或 waitpid() 对它进行清理,这时的进程状态称为僵死状态,处于僵死状态的进程称为僵尸进程(zombie process)。任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了。

僵尸进程是如何产生的

为了观察到僵尸进程,我们自己写一个不正常的程序,父进程 fork 出子进程,子进程终止,而父进程既不终止也不调用 wait 清理子进程:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> int main(void)
{
    int i = 100;
    pid_t pid=fork();
    if(pid < 0)
    {
        perror("fork failed.");
        exit(1);
    }
    if(pid > 0)
    {
        printf("This is the parent process. My PID is %d.\n", getpid());
        for(; i > 0; i--)
        {
            sleep(1);
        }
    }
    else if(pid == 0)
    {
        printf("This is the child process. My PID is: %d. My PPID is: %d.\n", getpid(), getppid());
    }
    return 0;
}

把上面的代码保存到文件 zomprocdemo.c 文件中,并执行下面的命令编译:

$ gcc zomprocdemo.c -o zomprocdemo

然后运行编译出来的 zomprocdemo 程序:

$ ./zomprocdemo

此时子进程已经退出,但是父进程没有退出也没有通过 wait() 调用处理子进程。我们使用 ps 命令查看进程的状态:

上图红框中的大写字母 "Z" 说明 PID 为 112712 的进程此时处于僵死的状态。

让我们接着往下看!在结束 sleep 后父进程退出。当父进程退出后,子进程会变成孤儿进程,此时它会被一个管理进程收养。在不同的系统中,这个管理进程不太一样,早期一般是 init 进程,Ubuntu 上是 upstart,还有近来的 Systemd。但是它们都完成相同的任务,就是 wiat() 这些孤儿进程,并最终释放它们占用的系统进程表中的资源。这样,这些已经僵死的孤儿进程就彻底的被清除了。

僵尸进程的危害

在进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号 PID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。

如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。

如何处理僵尸进程

僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要在父进程中通过 wait() 来避免僵尸进程的产生。

当系统中出现了僵尸进程时,我们是无法通过 kill 命令把它清除掉的。但是我们可以杀死它的父进程,让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。

下面的 demo 中,父进程通过 wait() 等待子进程结束:

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h> int main(void)
{
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fork failed");
        exit(1);
    }
    if (pid == 0) {
        int i;
         for (i = 3; i > 0; i--)
         {
            printf("This is the child\n");
            sleep(1);
         }
         // exit with code 3 for test.
        exit(3);
    }
    else
    {
        int stat_val;
        wait(&stat_val);
         if (WIFEXITED(stat_val))
         {
             printf("Child exited with code %d\n", WEXITSTATUS(stat_val));
         }            
    }
    return 0;
}

demo 中父进程不仅等待子进程结束,还通过 WEXITSTATUS 宏取到了子进程的 exit code。

Linux 僵尸进程如何处理的更多相关文章

  1. Linux 僵尸进程

    Linux 允许进程查询内核以获得其父进程的 PID,或者其任何子进程的执行状态.例如,进程可以创建一个子进程来执行特定的任务,然后调用诸如 wait() 这样的一些库函数检查子进程是否终止.如果子进 ...

  2. Linux 僵尸进程查杀

    僵尸进程概念 僵尸进程(Zombie process)通俗来说指那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸. 书面形式一点:一个进程结束了,但是他的父进程没有等待(调用wait ...

  3. Unix/Linux僵尸进程

    1. 僵尸进程的产生: 一个进程调用exit命令结束自己生命的时候,其实它并没有真正的被销毁,而是留下一个称为“僵尸进程”的数据结构.这时它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度 ...

  4. linux僵尸进程

    什么是僵尸进程?    在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程.  在fork()/execve()过程中,假设子 ...

  5. 转载 linux 僵尸进程,讲的很透彻

    僵尸进程的产生和避免,以及wait,waitpid的使用 在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitp ...

  6. linux僵尸进程产生的原因以及如何避免产生僵尸进程

    给进程设置僵尸状态的目的是维护子进程的信息,以便父进程在以后某个时间获取.这些信息包括子进程的进程ID.终止状态以及资源利用信息(CPU时间,内存使用量等等).如果一个进程终止,而该进程有子进程处于僵 ...

  7. 查看linux僵尸进程

    top ps -A -o stat,ppid,pid,cmd | grep -e '^[zZ]' kill -HUP 进程号

  8. linux 僵尸进程查看方式

    ps -A -ostat,ppid,pid,cmd |grep -e '^[Zz]' # 结果 Z 169925 49893 [sw] <defunct> Z 169925 120690 ...

  9. Linux 僵尸进程的筛选和查杀

    一.筛选 ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' 二.查杀 ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' ...

随机推荐

  1. 计算机与linux操作系统的发展

    一.计算机 (一)计算机的概念 1.概念:计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可以进行逻辑计算,还具有存储记忆功能.是能够按照程序运行,自动.高速 ...

  2. ZooKeeper环境搭建(单机/集群)(转)

    前提: 配置文件主要是在$ZOOKEEPER_HOME/conf/zoo.cfg,刚解压时为zoo_sample.cfg,重命名zoo.cfg即可. 配置文件常用项参考:http://www.cnbl ...

  3. QQ是怎样实现好友桌面快捷方式的?

    QQ是怎样实现好友桌面快捷方式的? 不知道什么时候,QQ推出了好友桌面快捷方式.方便用户和最常保持联系的好友一键联系.核心功能一:若QQ启动了.则双击快捷方式直接打开好友聊天界面:核心功能二:若QQ未 ...

  4. Java之POI读取Excel的Package should contain a content type part [M1.13]] with root cause异常问题解决

    Java之POI读取Excel的Package should contain a content type part [M1.13]] with root cause异常问题解决 引言: 在Java中 ...

  5. 阻塞、非阻塞、同步、异步IO

    阻塞.非阻塞.同步.异步IO http://www.cnblogs.com/yunxitalk/p/9031306.html 介绍 在谈及网络IO的时候总避不开阻塞.非阻塞.同步.异步.IO多路复用. ...

  6. NOIP2013--火柴排队(树状数组)

    转载: 树状数组,具体的说是 离散化+树状数组.这也是学习树状数组的第一题. 算法的大体流程就是: 1.先对输入的数组离散化,使得各个元素比较接近,而不是离散的, 2.接着,运用树状数组的标准操作来累 ...

  7. APP-Android:APK

    ylbtech-APP-Android:APK APK是AndroidPackage的缩写,即Android安装包(apk).APK是类似Symbian Sis或Sisx的文件格式.通过将APK文件直 ...

  8. 自顶向下(递归)的归并排序和自底向上(循环)的归并排序——java实现

    归并排序有两种实现方式,自顶向下和自底向上.前者的思想是分治法,现将数组逐级二分再二分,分到最小的两个元素后,逐级往上归并,故其核心在于归并.后者的思想相反,采用循环的方式将小问题不断的壮大,最后变成 ...

  9. 第2章 安装Nodejs 2-3 Windows下安装Nodejs

    http://nodejs.org

  10. GYM 100741A Queries(树状数组)

    A. Queries time limit per test 0.25 seconds memory limit per test 64 megabytes input standard input ...