当父进程在子进程死亡后不使用等待系统调用来读取其退出状态时,会创建一个Zombie,并且当原始父进程在子进程终止时,孤立是由init回收的子进程。
在内存管理和进程表方面,这些进程的处理方式有何不同,特别是在UNIX中?
当僵尸或孤儿的创建可能对更大的应用程序或系统有害时,有什么示例或极端情况?
答案 0 :(得分:81)
当一个孩子退出时,某个进程必须wait
才能获得其退出代码。退出代码存储在进程表中,直到发生这种情况。阅读退出代码的行为称为“收割”孩子。在孩子退出和收获之间,它被称为僵尸。 (当你想到它时,整个术语有点令人毛骨悚然;我建议不要过多考虑它。)
Zombies只占用进程表中的空间。它们不占用内存或CPU。但是,进程表是一个有限的资源,过多的僵尸可以填充它,这意味着没有其他进程可以启动。除此之外,它们很麻烦,应该强烈避免。
如果一个进程退出并且孩子仍在运行(并且没有杀死它的孩子;这个比喻仍然是奇怪的),那些孩子就是孤儿。孤立的孩子们被init
立即“收养”(实际上,我认为大多数人都称之为“重新定位”,但“收养”似乎更好地隐喻了)。孤儿只是一个过程。它将使用它使用的任何资源。可以合理地说,它不是一个“孤儿”,因为它有一个父母,但我听说他们经常这么说。
init
自动收回其子女(领养或其他)。因此,如果您在没有清理孩子的情况下退出,那么他们就不会成为僵尸(至少不会超过一会儿)。
但是存在着长寿的僵尸。这些是什么?他们是现有流程的前子女,并没有收获他们。这个过程可能会被挂起。或者它可能写得不好而忘记收获它的孩子。或者它可能超载并且没有得到它。管他呢。但由于某种原因,父进程仍然存在(因此它们不是孤儿),并且它们没有被等待,所以它们在进程表中以僵尸的形式存在。
因此,如果您看到僵尸的时间超过片刻,那么这意味着父进程出现问题,应该采取措施改进该程序。
答案 1 :(得分:15)
当进程终止时,其资源将由操作取消分配 系统。但是,它在进程表中的输入必须保持在那里直到 parent调用wait(),因为进程表包含进程的退出状态。 已终止但其父级尚未调用wait()的进程是 被称为僵尸进程。所有进程在转换到此状态时 终止,但通常它们仅作为僵尸短暂存在。一旦是父母 调用wait(),僵尸进程的进程标识符及其中的条目 进程表已经发布。
现在考虑如果父母没有调用wait()和会发生什么 而是终止,从而将其子流程保留为孤儿。 Linux和 UNIX通过将init进程指定为孤立进程的新父进程来解决此问题。 init进程定期进行 调用wait(),从而允许任何孤立进程的退出状态 收集并发布孤儿的进程标识符和进程表条目。
来自:操作系统概念 Abraham,Peter,Greg
答案 2 :(得分:9)
孤儿进程是parent process
已完成或终止的计算机进程,但它(子进程)仍在运行。
僵尸进程或已解散进程是一个已完成执行但仍在进程表中有条目的进程,因为其父进程未调用wait()
系统调用。
答案 3 :(得分:3)
僵尸进程: 已经完成执行但在进程表中仍有一个条目要报告给其父进程的进程称为僵尸进程。子进程在从进程表中删除之前总是首先变成僵尸进程。父进程读取子进程的退出状态,子进程从进程表中获取子进程条目。
孤儿进程: 父进程不再存在的进程,即在不等待其子进程终止的情况下完成或终止的进程称为孤儿进程。
答案 4 :(得分:2)
没有孤儿,但使用PID 1的过程。
从运行过程的角度来看,它是否直接启动并因此将PID 1作为父项或由PID 1继承而没有区别,因为它的原始父项(与PID 1不同)结束。 它的处理方式与其他任何流程一样。
每个过程在结束时经历某种僵尸状态,即通过发出SIGCHLD
并确认其处理(交付或无知)来宣告其结束之间的阶段。
当进入僵尸状态时,该过程只是系统进程列表中的一个条目。
僵尸专门使用的唯一重要资源是有效的PID。
答案 5 :(得分:2)
我想添加2个包含孤儿和僵尸进程的代码片段。但是首先,我将发布由Silberschatz,Galvin和Gagn撰写的“操作系统概念”一书中所述的这些过程的定义:
如果没有父等待(没有调用wait())过程是僵尸
如果父项终止而没有调用wait,则进程为 orphan
// 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;
}
输出
我的父母不等我
我不等我的孩子
编辑:来源和灵感来自here
答案 6 :(得分:1)
已完成执行但在进程表中仍具有要报告给其父进程的条目的进程称为僵尸进程。 父进程不再存在(即在不等待其子进程终止的情况下完成或终止)的进程称为孤立进程
答案 7 :(得分:1)
孤儿- 父出口,Init进程成为子进程的父进程。 这样子就终止了,进程表被操作系统删除了。
僵尸- 当孩子终止时,它将退出状态交给父母。 同时,时间假设您的父母处于睡眠状态。虽然孩子退出了,但是进程在进程表中占据了空间
在linux ubuntups -eo pid,ppid,status,cmd中签出此命令 如果您最后发现像defunc之类的东西,即您的进程是僵尸并占用了空间