僵尸进程

时间:2010-10-04 17:21:23

标签: c unix process posix systems-programming

我对僵尸进程有些疑问

  • 僵尸流程概念的好处是什么?
  • 知道内核为僵尸进程保留(PID,终止状态,资源使用信息) 什么是“资源使用信息”的含义
  • 僵尸的PPID()= 1并且它仍然是僵尸,(init收获Zombies因为它默认等待())
    任何人都可以写一些C代码来制作一个僵尸,它的父母是Init吗?
  • 僵尸可以拒绝释放一些内存锁吗?

提前致谢

4 个答案:

答案 0 :(得分:12)

- 僵尸流程概念的好处是什么?

僵尸进程只是一个pid,一个退出状态,以及一些会计信息,这些信息会一直存在,直到父级使用wait系列调用之一来获得其最终状态。在父母调用wait之前,子进程ID必须保持标记为已使用,以便不能为其分配任何其他进程。如果要为另一个进程分配一个回收的pid,则很难区分它与之前具有相同pid的进程之间的区别。一旦父母调用wait并返回最终退出状态,就可以假定没有人会再次在该pid处寻找孩子,因此现在可以重复使用pid。 (我认为在Linux上,如果父母将SIGCHLD作为SIG_IGN离开,内核将不会保留僵尸,但重新注册SIGCHLD的处置为SIG_IGN不具有相同的效果)

- 知道内核为僵尸进程保留(PID,终止状态,资源使用信息)“资源使用信息”是什么意思

其中一些信息是运行程序的:

time my_program

会报告。这些值通常在SIGCHLD的siginfo结构中报告(这不完全是对wait的调用),但也可以通过调用waitid形式的systme调用(在某些系统上)来获得。有关此结构的信息,请查看man sigaction

- 僵尸的PPID()= 1并且它仍然是僵尸,(init收获Zombies因为它默认等待())

一个僵尸的ppid = 1不应该长时间保持僵尸,因为 init 应该很快收获它。一个进程将在死亡后不久(通过exit或通过一个无效的信号杀死它)保持僵尸,直到其父级调用wait并获得它的最终状态。这意味着即使init除了一遍又一遍地调用init之外什么都不做,因此可能会有少量时间将进程显示为僵尸。如果进程在很长一段时间(秒)内显示为 init (0 = ppid)的子进程,则可能出现问题。

- 任何人都可以编写一些C代码来制作一个僵尸,它的父亲是Init?

目前尚不清楚,但我认为你想要:

pid_t f = fork();
if (f > 0) {
    exit(0); // this is the parent dying, so the child will be an orphan
             // and get adopted by init
} else if (f == 0) {
    sleep(100); // This is the child doing something that takes enough time for
                // its parent to commit suicide (exit(0)) and then for you to
                // observe that it has now been adopted by init
    exit(0);    // And now it dyes as well, so init should reap its status, but
                // it may be a zombie for a short amount of time first.
} else /* error condition would be handled here */

- 僵尸可以拒绝释放一些内存锁吗?

僵尸不能抓住任何东西。他们丢失了所有的内存页面,打开文件句柄等等。几乎所有操作系统都可以弄清楚如何释放应该被释放的东西。这不是一个错误,但请记住操作系统必须知道它应该被释放。在用户空间中创建资源非常容易,当程序死亡时,应该释放操作系统不知道应该被释放的资源。

答案 1 :(得分:3)

僵尸进程纯粹是一个pid和退出状态值。无法释放pid,因为资源(pid)“属于”父级。如果它被释放,另一个进程可能会被分配相同的pid,然后父进程可能最终向不相关的进程发送信号;即使父母首先等待确定孩子是否已经离开,也没有办法避免竞争条件。

答案 2 :(得分:2)

如果您有兴趣在正在运行的进程列表中查看僵尸进程,请使用以下命令:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
    pid_t p = fork();   // creates child process and stores the returned PID

    if (p != 0)         // executed by parent process
    {   sleep(1);       /* the child process terminates while the parent process sleeps,
                           the child then becomes a zombie process because the returned status
                           of the terminated child process isn't checked via a wait() */

        system("ps -eo pid,ppid,stat,cmd");  // prints a list of processes in your terminal

    }
    else        // executed by child process
    {
        exit(0);        // the child process terminates immediately
    }

    return 0;
}

您可以通过列表中的Z +识别僵尸进程:

screenshot of the zombie process

注意:如果您使用的是Windows,则必须修改代码。

答案 3 :(得分:0)

僵尸进程是已经停止运行的进程,但是它们的进程表条目仍然存在,因为父进程尚未通过wait syscall检索到它。从技术上讲,每个终止过程在很短的时间内都是僵尸,但它们可以生存更长的时间。

当子进程完成后父进程未调用wait syscall时,将出现更长的僵尸进程。发生这种情况的一种情况是,当父进程的编写不佳,只是省略了wait调用,或者当父进程在子进程之前死亡而新的父进程没有对其调用wait时。当进程的父进程在子进程之前死亡时,操作系统会将子进程分配给“ init”进程或PID1。即,init进程“采用”子进程并成为其父进程。这意味着现在子进程退出时,新的父进程(init)必须调用wait来获取其退出代码,否则其进程表条目将永远保留并成为僵尸。