
收藏夹
查看我的收藏夹
0有用+1投票
锁定
僵尸进程是子进程在父进程之前结束,并且父进程不回收子进程,从而释放了子进程占用的资源,此时子进程将成为僵尸进程. 如果父进程先退出,则子进程由init接管,子进程退出后,init将回收其占用的相关资源
我们都知道流程是如何工作的. 我们启动一个程序,开始我们的任务,然后当任务结束时,我们停止该过程. 进程停止后,将从进程表中删除该进程.
您可以通过系统监视器查看当前进度.
在UNIX系统术语中,已终止但其父级尚未等待的进程被称为僵尸. 在UNIX系统中,一个进程结束了,但是他的父进程不等待(调用wait / waitpid)他,那么他将成为僵尸进程. 但是,如果进程的父进程已先结束,则该进程将不会成为僵尸进程,因为在每个进程结束时,系统将扫描当前系统中运行的所有进程,以查看是否有任何进程仅仅是结束进程的子进程(如果有的话)将由Init接管并成为其父进程...
中文名称
僵尸进程
外语名称
僵尸进程
危险
因为系统无法产生新流程
主题
计算机
解决方案

可以使用kill-SIGKILL父进程ID来解决
实际上,当进程调用exit命令结束其生命时进程,它并没有真正被黑客入侵
僵尸进程
销毁,但保留一个称为Zombie的数据结构(系统调用出口,其作用是使进程退出,但仅限于将正常进程转变为僵尸进程,并且不能完全销毁它)
由于子进程的结束和父进程的运行是异步进程,也就是说,父进程永远无法预测子进程何时结束. 然后,父进程是否会太忙以至于无法等待子进程,或者说它不知道子进程,进程何时结束,并且子进程末尾的状态信息丢失?不会. 因为UNⅨ提供了一种机制,以确保只要父进程希望在子进程结束时知道状态信息,就可以获取该信息. 这种机制是: 当每个进程退出时,内核会释放该进程的所有资源,包括打开的文件,占用的内存等. 但是,仍然为其保留某些信息(包括进程ID,进程ID,终止状态). 进程,进程占用的CPU时间等). 直到父进程通过wait / waitpid来获取时,它才被释放. 但这会引起问题. 如果进程不调用wait / waitpid,则保留的信息将不会被释放,并且其进程号将始终被占用,但是系统可以使用的进程数是有限的. 如果生成大量僵尸进程,则系统将无法生成新进程,因为没有可用的进程号. 这是僵尸进程的危险,应避免.
避免僵尸进程
⒈父进程通过诸如wait和waitpid之类的功能等待子进程结束,这导致父进程挂起.
⒉如果父进程繁忙,则可以使用signal函数为SIGCHLD安装处理程序,因为在子进程结束后,父进程将接收到信号,并且可以在处理程序中调用wait进行回收.
⒊如果父进程不在乎子进程何时结束,则可以使用信号(SIGCHLD,SIG_IGN)通知内核您对子进程的结束不感兴趣,然后在子进程结束后,内核将被恢复,并且不再给父进程发送信号.
⒋还有一些技巧,即两次派生,父进程派生一个子进程,然后继续工作,子进程派生一个大进程,然后退出,然后大进程由init接管. ,并且盛大流程结束后,init将被回收. 但是进程,子进程的回收必须由您自己完成.
示例回顾我们在第8. 5节中有关僵尸过程的讨论. 如果我们要编写一个进程以使它派生一个孩子,但是我们不想等待孩子完成,并且我们不希望孩子成为僵尸直到我们终止,那么诀窍就是调用两次fork. 图8中的程序将执行此操作. 我们在第二个子进程中调用sleep,以确保第一个子进程在打印父进程ID之前终止. 分叉后,父母或孩子都可以继续执行;我们不知道哪个会先恢复执行.
如果我们没有让第二个孩子入睡,并且在第二个孩子在其父节点的fork之后恢复执行,则它打印的父流程ID将是其父节点的ID,而不是进程ID 1. 图8. 8给我们$. / 一个. out $第二个子进程,父进程pid = 1注意,当原始进程终止时(第二个子进程打印其父进程ID之前),shell将打印其提示符. 图8. 8.通过两次调用fork来避免僵尸进程
#include“ apue.h”
#include
int main(void)... {
pid_t pid;

如果((pid = fork())<0)
err_sys(“分叉错误”);
}否则,如果(pid == 0){/ *第一个孩子* /
如果((pid = fork())<0)
err_sys(“分叉错误”);
否则为(pid> 0)
退出(0); / *第二个分叉的父级==第一个孩子* /
/ *我们是第二个孩子;上面的语句中,我们真正的父母调用exit()时,我们的父母就成为了init. 在这里,我们将继续执行,知道完成后,init将会获得我们的地位. * /
睡觉⑵;
printf(“第二个孩子,父母pid =%d”,getppid());
退出(0);
if(waitpid(pid,NULL,0)!= pid)/ *等待第一个孩子* /
err_sys(“等待错误”);
/ *我们是父级(原始过程);我们继续执行,知道我们不是第二个孩子的父母. * /
退出(0);
它需要其父进程来为其收集尸体. 如果其父进程没有安装SIGCHLD信号处理函数调用wait或waitpid()以等待子进程结束,并且没有显式忽略该信号,则它一直处于僵尸状态;存在的问题: 如果父进程是一个循环并且不会结束,那么子进程将始终保持僵尸状态,这就是为什么系统中有时会有很多僵尸进程,可能会影响系统性能的原因. 如果父进程此时结束,则init进程将自动接管子进程并为其收集尸体,但仍可以将其清除. 4.为什么子进程结束后子进程会进入僵尸状态?因为父进程可能要获取子进程的退出状态和其他信息. 5.僵尸状态是每个子进程的必要状态吗?是. 任何子进程(init除外)都不会在exit()之后立即消失,而是留下一个称为Zombie的数据结构,等待父进程进行处理. 这是每个子进程最后必须经过的阶段. 如进程在exit()之后没有时间进行处理,则可以使用ps命令查看子进程的状态为“ Z”. 如果父进程可以及时处理它,那么使用ps命令查看子进程的僵尸状态可能为时已晚,但这并不意味着子进程不会经历僵尸状态. *如果父进程在子进程结束之前退出,则子进程将由init接管. 初始化会将僵尸状态的子进程作为父进程进行处理. 6.如何查看僵尸进程: $ ps -el其中,标记为Z的进程是僵尸进程S代表睡眠状态; D代表不间断的睡眠状态; R代表运行状态; Z代表僵尸状态; T代表停止或跟踪状态
在fork()/ execve()进程中,假定子进程结束时父进程仍然存在,并且父进程fork()尚未安装SIGCHLD信号处理函数调用waitpid()来等待子进程结束,并且没有明显的信号. 如果忽略该信号,则该子进程成为僵尸进程,无法正常结束. 此时,即使根身份kill -9也无法杀死僵尸进程.

杀死僵尸进程的父进程(僵尸进程的父进程必须存在),僵尸进程成为“孤儿进程”,继承到进程1的init,init将始终负责清理僵尸进程.
实际上,当进程通过调用exit命令结束其生命时,
Linux中的僵尸进程
它实际上并没有被销毁,而是留下了一个称为Zombie的数据结构(系统调用出口,其作用是使进程退出,但仅限于将正常进程转变为僵尸进程无法完全销毁它). 在Linux进程的状态下,僵尸进程是一种非常特殊的类型. 它几乎放弃了所有的内存空间,没有可执行代码,因此无法计划. 它只是在流程列表中保留一个位置并记录流程的退出. 状态等信息是由其他进程收集的. 此外,僵尸进程不再占用任何内存空间. 它需要其父进程来为其收集尸体. 如果其父进程未安装SIGCHLD信号处理函数来调用wait或waitpid()以等待子进程结束,并且未显式忽略该信号,则它将保持僵尸状态,如果此时父进程结束,则init进程将自动接管子进程,为其收集主体,仍可以清除它. 但是,如果父进程是一个循环并且不会结束,那么子进程将始终保持僵尸状态,这就是为什么系统中有时会有很多僵尸进程的原因.
检查僵尸进程. 使用ps命令,您可以看到标记为Z的进程是僵尸进程.
具体步骤
1)在SVR4中,如果调用signal或sigset将SIGCHLD配置设置为忽略,则不会有死子进程. 此外,使用SVR4版本的sigaction,您可以设置SA_NOCLDWAIT标志以避免子进程死锁.
这也可以在Linux中使用,请在程序开头调用此函数
信号(SIGCHLD,SIG_IGN);
2)两次呼叫fork. 步骤8-5实现了这一目标.
3)使用waitpid等待子进程返回.
=========================================
僵尸进程是僵尸进程. 防止它的方法是使用wait和waitpid等功能获取它
释放资源的进程的终止状态. 另一种是叉两次
=========================================
已终止的进程仅在进程表中有一条记录,而其他资源则未被占用. 除非超出系统中进程数的限制,否则僵尸进程不会造成更大的危害.

一种可能的方法是重新启动系统以消除僵尸进程.
=========================================
任何程序都具有僵尸状态. 它占用了一些内存资源(即,进程表中有一条记录). 这只是一种代表,您不必担心. 如果程序存在问题,并且有机会解决该问题,那么解决大量僵尸的简单有效方法是重新启动. 杀死没有效果
“重获新生”
某些进程如何在Unix下工作. 进程死亡时,它不会完全消失. 该进程已终止,不再运行,但是仍有一些小事情等待父进程恢复. 这些残留的东西包括子进程的返回值和其他一些东西. 当父进程派生()子进程时,它必须等待()或waitpid()以等待子进程退出. 正是这种wait()动作使子进程的剩余部分消失了.
自然,上述规则有一个例外: 父进程可以忽略SIGCLD软中断而无需等待(). 可以做到这一点(在支持它的系统上,例如Linux):
主要()
信号(SIGCLD,SIG_IGN); / *现在,我不必等待()! * /
叉子();
叉子();
fork(); / *兔子,兔子,兔子! * /
当前子进程死亡时,父进程没有wait(),通常ps可被视为“”. 它将一直保持这种状态,直到父进程wait()或以以下方式对其进行处理.
这是您必须知道的另一条规则: 当父进程在其wait()子进程之前死亡(假设它不忽略SIGCLD)时,子进程会将init(pid 1)进程视为其父进程. 如进程运行良好并且可以控制,那么这不是问题. 但是,如进程已经不存在,我们会遇到一些麻烦. 请参阅,原始父进程无法等待(),因为它已经死亡. 这样,init如何知道wait()的僵尸进程?
答案: 不可预测. 在某些系统上,init会定期破坏其所有已终止的进程. 在其他系统中,它只是拒绝成为任何已终止进程的父级,而是立即销毁它们. 如果使用上述系统之一,则可以编写一个简单的循环,用属于init的已终止进程填充进程表. 这可能不会使您的系统管理员满意?
您的任务: 确保您的父进程不忽略SIGCLD,也不要等待()所有对其进行分叉()的进程. 但是,您不必总是这样做(例如,如果您想启动守护程序之类的东西),但是如果您是新手,请务必谨慎进行派生(). 此外,没有任何心理限制.
重写父进程
具体方法是接管SIGCHLD信号. 子进程死后,它将向父进程发送SIGCHLD信号. 接收到信号后,父进程将执行waitpid()函数来为子进程收集主体. 它基于此原则: 即使父进程不调用wait,内核也会向其发送SIGCHLD消息. 此时,尽管默认处理是忽略它,但是如果您想响应此消息,则可以设置处理功能.
杀死父进程
父进程死亡后,僵尸进程成为“孤立进程”,该进程将传递给进程1的init. init始终负责清理僵尸进程. 它产生的所有僵尸进程也消失了.
=========================================
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-202761-1.html
国家连年扩招