关于僵尸进程和孤儿进程

xiaoxiao2021-02-27  421


tittle:关于僵尸进程和孤儿进程

进程的几种状态

R状态 进程要么在运行要么在运行队列中。S状态 睡眠状态,进程在等待某事件完成(可被中断)D状态 不可中断的睡眠状态(通常其在第等待IO结的束)T状态 被停止的进程 (发送信号SIGSTOP停止进程 SIGCONT让进程继续运行)X状态 进程已死 已被回收 kernel你的do_exit函数返回的状态。Z状态 僵尸进程。。。

僵尸进程的产生

“僵尸”进程是什么?通常情况下,僵尸进程的成因是因为该进程已经执行完毕,但是该进程的父进程却无法完整的将该进程结束掉(如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,即未接受其退出状态信息,那么它就一直保持僵尸状态),而造成该进程一直存在于内存中。

一个进程在调用exit命令结束自己的生命的时候,其实 它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)所以僵尸进程需要父进程彻底结束他。

查看僵尸进程

那么如何查看一个进程是否为僵尸进程呢?

ps:将某个时间点的进程运行状态选取下来

ps aux //查看系统所有的进程数据 -A:所有的进程均显示出来 -a:不与terminal有关的所有进程 -u:有效用户相关的进程 -x:通常与a一起使用,可以列出较完整的信息 -l:较长、较详细地将该PID的信息列出

当你获知它是一个僵尸进程后,那么你该如何干掉它呢,那么首先就得了解一下进程的管理。

程序之间的相互管理,是通过给予一个信号来进行管理的

查看信号(signal): 1、man 7 signal 2、kill -l

这里显示的是一些操作进程所需要的信号及其编码。

通常情况下,我们只需记住几个特别重要的信号即可。

1:启动被终止的进程,可让该PID重新读取自己的配置文件 9:强制中段一个进程,如果该进程运行到一半(如vim)会产生.filename.swap的半产品文件 15:正常结束一个进程 18:继续运行该进程 19:暂停一个进程

kill -9 (+进程的pid)可以杀死这个进程

模拟一个僵尸进程

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 #include<errno.h> 5 6 7 void FunTest() 8 { 9 pid_t pid; 10 pid = fork(); 11 12 if(pid < 0) 13 { 14 perror("fork error"); 15 exit(1); 16 } 17 else if(0 == pid) 18 { 19 printf("I am the child process.I am exiting\n"); 20 exit(0); 21 } 22 printf("I am father process.i will sleep two seconds\n"); 23 sleep(2); 24 system("ps -o pid,ppid,state,tty,command"); 25 printf("father process is exiting\n"); 26 } 27 28 int main() 29 { 30 FunTest(); 31 return 0; 32 }

执行结果:43645成为僵尸进程

模拟实现多个僵尸进程

父进程循环创建子进程,子进程退出,造成多个僵尸进程。

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 #include<errno.h> 5 6 7 void FunTest() 8 { 9 pid_t pid; 10 int n = 3; 11 while(n){ 12 n--; 13 pid = fork(); 14 15 if(pid < 0) 16 { 17 perror("fork error"); 18 exit(1); 19 } 20 else if(0 == pid) 21 { 22 printf("I am the child process.I am exiting\n"); 23 exit(0); 24 } 25 else{ 26 sleep(1); 27 continue; 28 } 29 30 } 31 printf("I am father process .I will sleep two second\n"); 32 sleep(2); 33 system("ps -o pid,ppid,state,tty,command"); 34 printf("father process is exting\n"); 35 36 } 37 38 int main() 39 { 40 FunTest(); 41 return 0; 42 }

执行结果:43963 43964 43965三个僵尸进程

僵尸进程解决办法

通过信号量机制

子进程退出时向父进程发出SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<errno.h> 4 #include<unistd.h> 5 #include<signal.h> 6 #include<sys/wait.h> 7 8 static void sig_child (int signo) 9 { 10 pid_t pid; 11 int status; 12 //deal Jiangshi process 13 while((pid == waitpid(-1,&status,WNOHANG)) > 0) 14 { 15 printf("child %d terminated\n",pid); 16 } 17 } 18 19 int main() 20 { 21 pid_t pid; 22 pid = fork(); 23 signal(SIGCHLD,sig_child); 24 if(pid < 0) 25 { 26 perror("fork error"); 27 exit(1); 28 } 29 else if(0 == pid) 30 { 31 printf("I am the child process. I am exiting\n"); 32 exit(0); 33 } 34 printf("I am the father process. I will sleep two seconds\n"); 35 sleep(2); 36 system("ps -o pid,ppid,state,tty,command"); 37 printf("father process is exiting\n"); 38 return 0;

运行结果:僵尸进程被父进程成功回收。

关于孤儿进程

一个父进程退出后,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 #include<errno.h> 5 6 int main() 7 { 8 int pid = fork(); 9 if(-1 == pid) 10 { 11 perror("fork error"); 12 } 13 else if(0 == pid) 14 { 15 printf("child is %d,father is %d\n",getpid(),getppid()); 16 sleep(2); 17 } 18 else{ 19 printf("father is %d,child is %d\n",getppid(),getpid()); 20 printf("father process is exuted\n"); 21 } 22 return 0; 23 }

僵尸进程危害场景:

  例如有个进程,它定期的产生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样系统运行上一段时间之后,系统中就会存在很多的僵死进程。   倘若用ps命令查看的话,就会看到很多状态为Z的进程。 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。   那我们该如何消灭系统中大量的僵死进程呢?答案就是把产生大量僵死进程的那个元凶杀掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。杀掉元凶进程之后,它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了

转载请注明原文地址: https://www.6miu.com/read-350.html

最新回复(0)