僵尸进程简介
“僵尸”进程是什么?通常情况下,造成僵尸进程的成因是因为该进程本应该已经执行完毕,但是该进程的父进程却无法完整的将该进程结束掉,而造成该进程一直存在于内存中。
那么如何查看一个进程是否为僵尸进程呢?
ps:将某个时间点的进程运行状态选取下来 ps aux //查看系统所有的进程数据 -A:所有的进程均显示出来 -a:不与terminal有关的所有进程 -u:有效用户相关的进程 -x:通常与a一起使用,可以列出较完整的信息 -l:较长、较详细地将该PID的信息列出
如上图
也可以通过top指令来查看是否存在僵尸进程
top:动态查看进程的变化 top:参数 -d:后面接秒数,表示显示整个进程界面更新的秒数,如top -d 5 -b:以批次的方式执行top -n:与-b搭配,意思是需要几次top输出的结果 -p:指定某个特定的PID进行检测
光标处即目前的僵尸进程数量。
举例
这是一个维持30秒的僵尸进程
#include
#include
int main(int argc,char argv[]) { int id = fork(); if(id>0) { printf("Parent is sleeping\n"); sleep(30); } if(id == 0) printf("Child process is done\n"); exit(EXIT_SUCCESS); }
通俗一点,僵尸进程就是指子进程先于父进程挂掉 但是父进程并没有正确回收子进程的资源而已。
进程的管理
当你获知它是一个僵尸进程后,那么你该如何干掉它呢,那么首先就得了解一下进程的管理。
程序之间的相互管理,是通过给予一个信号来进行管理的

总的来说,当系统不稳定时,或者代码不够完善,亦或是用户操作不当都可能产生僵尸进程,而僵尸进程是1个早已死亡的进程,但在进程表(processs table)中仍占了1个位置(slot)。由于进程表的容量是有限的,所以就占用了内存资源,影响系统性能。
补充:
如何防止僵尸进程的产生
如上所述,当子进程先行退出,且父进程不对其做回收的话,会产生僵尸进程,我们可以通过的进程等待,来让父进程等待子进程退出然后进行回收。
具体的进程等待这里就不赘述了。可以参考进程控制中的进程等待部分。
这里主要是为了提一下后续学到了信号部分的知识,当子进程退出时操作系统会发送SIGCHLD信号,而该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程就可以处理自己的事情,而不必关心子进程的退出,在父进程的处理函数中调用wait清理子进程即可。
看如下代码:
#include
#include
#include
#include
#include
#include
//自定义SIGCHLD信号的处理函数,对子进程进程wait void Myhandler(sigset_t signal) { printf("wait\n"); wait(NULL); } int main() { //当收到SIGCHLD信号时,执行自定义的处理函数 signal(SIGCHLD,Myhandler); pid_t id = fork(); if(id > 0){ //father while(1){ printf("father doing some thing!\n"); sleep(1); } }else if(id == 0){ //child sleep(3); exit(1); }else{ perror("fork"); return 1; } return 0; }
void Myhandler(sigset_t signal) { printf("wait\n"); wait(NULL); } int main() { signal(SIGCHLD,Myhandler); pid_t cid; int i = 0; for(;i < 20;++i) { cid = fork(); if(cid == 0) exit(0); } if(cid > 0) { while(1) { printf("father doing some thing!\n"); sleep(1); } } else if(cid == 0) { sleep(3); } return 0; }
可以看到,只wait了15次,这样意味着产生了5个僵尸进程,来查看一下系统中是否真的出现了5个僵尸进程。
解释下为什么会出现僵尸进程,因为操作系统在接受到一个信号时,在执行处理函数时,就会屏蔽该信号,所以当有多个子进程同时退出发送信号时,操作系统就收到一个信号,所以就造成僵尸进程的出现。
基于这个问题,可以采用两种发生来解决。
一:一次处理函数wait多个子进程
void Myhandler(sigset_t signal) { pid_t id; while((id = waitpid(-1,NULL,WNOHANG) > 0)){ printf("child wait success:%d\n",id); } printf("child is quit!\n"); } int main() { signal(SIGCHLD,Myhandler); pid_t cid; int i = 0; for(;i < 20;++i) { cid = fork(); if(cid == 0) exit(0); } if(cid > 0) { while(1) { printf("father doing some thing!\n"); sleep(1); } } else if(cid == 0) { sleep(3); } return 0; }
由于篇幅问题,有一点没截上,可以看到子进程全部被回收了,系统中并没有产生僵尸进程。
二:使用sigaction函数
int main() { struct sigaction new,old; new.sa_handler = SIG_IGN; sigemptyset(&new.sa_mask); new.sa_flags = 0; sigaction(SIGCHLD,&new,&old); pid_t cid; int i = 0; for(;i < 20;++i) { cid = fork(); if(cid == 0) exit(0); } if(cid > 0) { while(1) { printf("father doing some thing!\n"); sleep(1); } } else if(cid == 0) { sleep(3); } sigaction(SIGCHLD,&old,NULL); return 0; }
就先补充到这了,后续有新的理解,会继续更新。
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/205533.html原文链接:https://javaforall.net
