僵尸进程

当一个进程终止时,操作系统会释放其资源,不过它位于进程表中的条目还是在的,直到它的父进程调用wait();这是因为进程表中包含了进程的退出状态。当进程已经终止,但是其父进尚未调用wait(),这样的进程叫做僵尸进程(zombie prpcess)。

所有进程终止时都会过度到这种状态,但是一般而言僵尸只是短暂存在。一旦父进程调用了wait(),僵尸进程的进程标示符和它在进程表中的条目就会释放。

这里需要注意:僵尸进程不能通过kill来进行杀死,因为kill是用来终止进程的,僵尸进程已经是终止的。

设计一个僵尸进程:
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <signal.h> //僵尸进程
int main(void) { pid_t pid; printf("before fork pid:%d\n", getpid()); int abc = 10; pid = fork();
if(pid < 0) {
fprintf(stderr, "fork failed");
return 1; }
else if(pid == 0) {
abc++;
printf("child:%d, parent:%d\n",getpid(), getppid());
printf("abc:%d", abc);
exit(0);
}
else {
abc++;
printf("parent:pid:%d \n", getpid());
printf("abc:%d \n", abc);
sleep(20);
} printf("fork after ... \n"); }

执行结果:

shanlei@shanlei-Lenovo-ideapad-110-15ISK:/var/www/c_code/操作系统$ ./2
before fork pid:7203
parent:pid:7203
abc:11
child:7204, parent:7203
abc:11fork after ...
shanlei@shanlei-Lenovo-ideapad-110-15ISK:/var/www/c_code/操作系统$

查看运行时的进程表:

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY        TIME CMD
0 S 1000 7203 5576 0 80 0 - 1127 hrtime pts/0 00:00:00 2
1 Z 1000 7204 7203 0 80 0 - 0 - pts/0 00:00:00 0
4 R 1000 7205 7084 0 80 0 - 9006 - pts/1 00:00:00 ps

注意:在进程表中进程状态位于列S,状态位为Z的是僵尸进程,子进程的进程标识符(pid)位于列PID,而父进程的标识符则位于列PPID。

僵尸进程的危害:

如果不调用wait / waitpid的话,保留的那段信息可能会一直存在,那么将会一直占用着进程号,如果系统中存在大量的僵尸进程,将会造成进程号短缺而无法产生新进程。并且很可能造成资源泄露。

如何避免僵尸进程

1.通过信号机制,子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait/waitpid进行处理僵尸进程。代码如下:

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <signal.h>
static void sig_child(int signo); //僵尸进程
int main(void) { pid_t pid; printf("before fork pid:%d\n", getpid()); //采用信号量机制
signal(SIGCHLD, sig_child); int abc = 10; pid = fork();
if(pid < 0) {
fprintf(stderr, "fork failed");
return 1; }
else if(pid == 0) {
abc++;
printf("child:%d, parent:%d\n",getpid(), getppid());
printf("abc:%d", abc);
exit(0);
}
else {
abc++;
printf("parent:pid:%d \n", getpid());
printf("abc:%d \n", abc);
sleep(20);
} printf("fork after ... \n"); } static void sig_child(int signo) {
pid_t pid;
int stat;
while((pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child pid=%d terminated.\n", pid);
}

2.或者fork两次,原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。(这种方法不是很理解,所以没有代码…哪位好心人能给我讲一讲吗?)

孤儿进程

如果父进程没有调用wait()就终止了,那么对于该父进程的子进程将会成为孤儿进程(orphan process)。Linux/Unix对这种情况的处理是:将init进程作为孤儿进程的父进程,进程init定期调用wait(),以便收集任何孤儿进程的退出状态,并释放孤儿进程标识符和进程表条目。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h> //孤儿进程
int main(void) { pid_t pid;
pid = fork(); if(pid < 0) {
fprintf(stderr, "fork failed");
return 1;
}
else if(pid == 0) {
printf("I am Child, pid=%d, ppid=%d\n", getpid(), getppid());
sleep(10);
printf("I am Child, pid=%d, ppid=%d\n", getpid(), getppid());
}
else {
sleep(1);
printf("I am Parent, pid=%d\n", getpid());
} return 0;
}

执行结果:

shanlei@shanlei-Lenovo-ideapad-110-15ISK:/var/www/c_code/操作系统$ ./3
I am Child, pid=8300, ppid=8299
I am Parent, pid=8299
shanlei@shanlei-Lenovo-ideapad-110-15ISK:/var/www/c_code/操作系统$ I am Child, pid=8300, ppid=1

进程表条目:

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
4 S 0 1 0 0 80 0 - 56380 - ? 00:00:09 systemd
....
1 S 1000 8300 1 0 80 0 - 1127 hrtime pts/0 00:00:00 3
4 R 1000 8301 7084 0 80 0 - 9006 - pts/1 00:00:00 ps

由于子进程sleep了10s,所以父进程终止时,子进程还没有结束,此时将会该子进程成为孤儿进程,可以看到这个时候该孤儿进程的父进程PID为1,也就是所谓的systemd(init)进程。

init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

OS之进程管理---孤儿进程和僵尸进程的更多相关文章

  1. 进程——wait与waitpid、僵尸进程与孤儿进程

    僵尸进程:子进程终止了,但是父进程没有回收子进程的资源PCB.使其成为僵尸进程 孤儿进程:父进程先与子进程结束了,使得子进程失去了父进程,这个时候子进程会被1号进程init进程领养,成为孤儿进程 为了 ...

  2. Linux进程实践(4) --wait避免僵尸进程

    Wait的背景 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程 ...

  3. [20180312]进程管理其中的SQL Server进程占用内存远远大于SQL server内部统计出来的内存

    sql server 统计出来的内存,不管是这个,还是dbcc memorystatus,和进程管理器中内存差距很大,差不多有70G的差异. 具体原因不止,可能是内存泄漏,目前只能通过重启服务解决   ...

  4. Linux进程管理 lsof命令:列出进程调用或打开的文件信息

    lsof命令 通过 ps 命令查询到系统中所有的进程, 通过lsof 命令可以知道这个进程到底在调用哪些文件.lsof 命令格式如下: [root@localhost ~]# lsof [选项] 选项 ...

  5. python学习笔记—— 多进程中的 孤儿进程和僵尸进程

    1 基本概述 1.1 孤儿进程和僵尸进程 父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源:而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调 ...

  6. Python脚本模拟僵尸进程与孤儿进程

    最近一台机器的systemd内存高达30%多,一直不变,后来排查是僵尸进程,什么是僵尸进程呢,只能google,百度等先了解,然后自己总结了一下,虽然这是基础的东西,但是对于我来说就如新大陆一样.花了 ...

  7. day34——僵尸进程和孤儿进程、互斥锁、进程之间的通信

    day34 僵尸进程和孤儿进程 基于unix环境(linux,macOS) 主进程需要等待子进程结束之后,主进程才结束 主进程时刻监测子进程的运行状态,当子进程结束之后,一段时间之内,将子进程进行回收 ...

  8. 僵尸进程 & 孤儿进程

    参考博文 基本概念 僵尸进程:是所有进程都会进入的一种进程状态,子进程退出,而父进程并没有调用 wait() 或 waitpid() 获取子进程的状态信息,那么子进程的 PID 和 进程描述符 等资源 ...

  9. [并发编程 - socketserver模块实现并发、[进程查看父子进程pid、僵尸进程、孤儿进程、守护进程、互斥锁、队列、生产者消费者模型]

    [并发编程 - socketserver模块实现并发.[进程查看父子进程pid.僵尸进程.孤儿进程.守护进程.互斥锁.队列.生产者消费者模型] socketserver模块实现并发 基于tcp的套接字 ...

随机推荐

  1. head first 设计模式文摘

    1 欢迎来到设计模式世界:设计模式入门 2 让你的对象知悉现况:观察者模式 3 装饰对象:装饰者模式 4 工厂模式:烘烤OO的精华 5 单件模式:独一无二的对象 6 命令模式:封装调用 7 适配器模式 ...

  2. HDU 2561 第二小整数 (排序)

    题意:中文题. 析:输入后,排一下序就好. 代码如下: #include <iostream> #include <cstdio> #include <algorithm ...

  3. DIV+CSS实战(一)

    一.说明 作为一个后台的程序员,我也是很少写前端,最近有一个项目,前端主要是由我来负责,就把我在项目中所学到的东西,记录下来!我的页面要嵌入到另一个系统中,所以,并不是按照传统的top,left,co ...

  4. Spring bean是如何加载的

    Spring bean是如何加载的 加载bean的主要逻辑 在AbstractBeanFactory中doGetBean对加载bean的不同情况进行拆分处理,并做了部分准备工作 具体如下 获取原始be ...

  5. Android基础之使用Fragment控制切换多个页面[转]

    Android官方已经提供了Fragment的各种使用的Demo例子,在我们SDK下面的API Demo里面就包含了Fragment的各种使用例子,需要看Demo的朋友,直接看API Demo那个程序 ...

  6. Node.js使用MySQL的连接池

    使用Nodejs+MySQL肯定比PHP和MySQL的组合更适合做服务器端的开发. 使用Nodejs你会从他的异步行为中获益良多.比如,提升性能,你无须在从已有的MySQL数据库迁移到其他的NoSQL ...

  7. HDU4081 Qin Shi Huang's National Road System 2017-05-10 23:16 41人阅读 评论(0) 收藏

    Qin Shi Huang's National Road System                                                                 ...

  8. 从hbase到hive,以及sqoop转到mysql解析

    https://blog.csdn.net/qq_33689414/article/details/80328665 hive关联hbase的配置文件 hive和hbase同步https://cwik ...

  9. hdu 5038 求出现次数最多的grade

    http://acm.hdu.edu.cn/showproblem.php?pid=5038 模拟水题 求出现次数最多的grade.如果有多个grade出现的次数一样多,且还有其他的grade,则把这 ...

  10. Example11(June 9,2015)

    %--------------sort------------------------------- >> A=[ ; ; ] A = >> B=sort(A,)%A(:,)& ...