僵尸进程与孤儿进程

当一个子进程死亡后,父进程没有使用等待系统调用来读取它的退出状态时,就会创建一个 Zombie,孤儿是子进程,当原始父进程在子进程之前终止时,init 会回收这个子进程。

在内存管理和进程表方面,如何以不同的方式处理这些进程,特别是在 UNIX 中?

当僵尸或孤儿的创建可能对更大的应用程序或系统有害时,什么是例子或极端情况?

89983 次浏览
  1. 除了使用 PID 1的进程之外,没有孤儿。

    从正在运行的进程的角度来看,它是直接启动的并且因此具有 PID 1作为父进程,还是由 PID 1继承的,因为它的原始父进程(与 PID 1不同)结束了,这没有什么区别。 它的处理方式和其他进程一样

  2. 每个进程在结束时都会经历某种僵尸状态,即从通过发出 SIGCHLD来宣布结束到确认其处理(传递或无知)之间的阶段。

当进入僵尸状态时,进程只是系统进程列表中的一个条目。

僵尸唯一独占使用的重要资源是有效的 PID。

当一个子进程退出时,某个进程必须对其执行 wait才能获得其退出代码。该退出代码存储在流程表中,直到发生这种情况。读取退出代码的行为称为“收割”子代。在孩子出生和被收割之间,它被称为僵尸。(如果你仔细想想,整个命名方法有点可怕; 我建议你不要想得太多。)

僵尸只占用进程表中的空间。它们不占用内存和 CPU。然而,进程表是一个有限的资源,过多的僵尸可以填充它,这意味着没有其他进程可以启动。除此之外,它们还是令人讨厌的杂物,应该强烈避免。

如果一个进程退出时子进程仍在运行(并且没有杀死它的子进程; 这个比喻仍然很奇怪) ,那么这些子进程就是孤儿。孤儿立即被 init“收养”(实际上,我认为大多数人称之为“再教育”,但“收养”似乎更能体现这个比喻)。孤儿只是一个过程。它将使用它所使用的任何资源。有理由说它根本不是“孤儿”,因为它有父母,但我经常听到他们这样叫它。

init自动收割其子女(收养或其他)。因此,如果你离开时没有清理你的孩子,那么他们不会成为僵尸(至少不会超过一个瞬间)。

但是长寿僵尸是存在的。他们是什么?他们是一个现存的过程的前孩子,这个过程还没有收获他们。该过程可能被挂起。或者,它可能写得很糟糕,忘记了收割它的孩子。也可能是超载了,还没来得及修。或者别的什么。但出于某种原因,父进程继续存在(所以他们不是孤儿) ,他们没有被等待,所以他们作为僵尸生活在进程表中。

所以如果你看到僵尸超过一会儿,那就意味着父进程出了问题,应该做些什么来改进这个程序。

当进程终止时,其资源由操作释放 但是,它在流程表中的条目必须保留在那里,直到 父调用 wait () ,因为进程表包含进程的退出状态。 已终止但其父进程尚未调用 wait ()的进程为 所有的进程都会转换到这个状态,当它们 终结,但通常他们作为僵尸存在只是短暂的。一旦父母 调用 wait ()、僵尸进程的进程ID 及其在 程序表被释放。

现在考虑一下如果父类不调用 wait ()和 而是终止,从而将其子进程保留为 孤儿.Linux 和 UNIX address this scenario by assigning the init process as the new parent to orphan processes. The init process periodically 调用 wait () ,从而允许任何孤立进程的退出状态为 收集并发放孤儿的进程ID 和处理表条目。

资料来源: 操作系统概念 by 亚伯拉罕,彼得,格雷格

孤儿过程是一个计算机进程,它的 parent process已经完成或终止,但是它(子进程)仍然在运行。
僵尸过程或失效进程是一个已经完成执行但仍然在进程表中有一个条目的进程,因为它的父进程没有调用 wait()系统调用。

已完成执行但仍有进程表中的条目要向其父进程报告的进程称为僵尸进程。 如果一个进程的父进程不再存在,例如完成或终止而不等待其子进程终止,则该进程称为孤立进程

孤儿 父进程退出,Init 进程成为子进程的父进程。 每当子进程被终止,进程表就会被 OS 删除。

僵尸 当子节点终止时,它将退出状态发送给父节点。 与此同时,假设你的父母处于睡眠状态,无法从孩子那里获得任何状态。 虽然子进程退出但进程在进程表中占有空间

在 linux ubuntu > ps-eo pid,ppid,status,cmd 中查看这个命令

如果你在最后发现了类似 defunc 的东西,也就是说你的过程是僵尸和占用空间。

我想添加2个代码片段,其中包含一个孤儿和一个僵尸进程。但是首先,我将发布 Silberschatz,Galvin 和 Gagn 在《操作系统概念》一书中对这些过程的定义:

如果没有父进程等待(没有调用 wait ())进程,则为 僵尸

如果父进程在没有调用 wait 的情况下终止,则进程为 孤儿

孤儿

// A C program to demonstrate Orphan Process.
// Parent process finishes execution while the
// child process is running. The child process
// becomes orphan.


#include <stdio.h>  //printf
#include <stdlib.h> //exit
#include <sys/types.h> //fork
#include <unistd.h> //fork and sleep
  

int main()
{
// Fork returns process id
// in parent process
pid_t child_pid = fork();
  

// Parent process didn't use wait and finished before child
// so the child becomes an orphan process


// Parent process
if (child_pid > 0) {
printf("I finished my execution before my child");
}
else // Child process
if (child_pid == 0) {
sleep(1); //sleep for 1 second
printf("This printf will not be executed");
}
else{
//error occurred
}
  

return 0;
}

输出

我在孩子出生前就结束了死刑

僵尸

// A C program to demonstrate Zombie Process.
// Child becomes Zombie as parent is not waiting
// when child process exits.


#include <stdio.h>  //printf
#include <stdlib.h> //exit
#include <sys/types.h> //fork
#include <unistd.h> //fork and sleep


int main()
{
// Fork returns process id
// in parent process
pid_t child_pid = fork();
 

// Parent process didn't use wait
// so the child becomes a zombie process


// Parent process
if (child_pid > 0){
sleep(1); //sleep for 1 second
printf("\nI don't wait for my child");
}
else // Child process
if(child_pid == 0){
printf("My parent doesn't wait me");
exit(0);
}
else{
//error occurred
}
    

return 0;
}

输出

我父母不等我

我不等我的孩子

编辑: 来源和灵感来自 给你

僵尸过程: 已经完成执行但仍然在进程表中有一个条目要报告给其父进程的进程称为僵尸进程。子进程在从进程表中删除之前总是首先变成僵尸进程。父进程读取子进程的退出状态,该子进程从进程表中获取子进程条目。

孤儿过程: 如果一个进程的父进程不再存在,例如完成或终止而不等待其子进程终止,则该进程称为孤立进程。

以下是每个 医生的摘要

僵尸程序 孤儿程序
Zombie 是一个已经完成任务的流程,但它仍然显示流程表中的一个条目。 即使在其父进程终止或完成而没有等待子进程执行之后仍在运行的子进程称为孤立进程。
僵尸进程状态始终由 Z 表示 由于系统崩溃,在不知情的情况下创建了孤立进程。
僵尸进程被视为死进程,它们不用于系统处理 孤立进程是一个计算机进程,即使在它们的父进程终止之后,init 也会成为父进程并继续剩余的任务。
要删除僵尸进程,请执行 kill 命令。 使用 SIGHUP 信号终止孤立进程。

另一个很好的 文章列出了一些场景。