博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux 僵尸进程
阅读量:6258 次
发布时间:2019-06-22

本文共 2752 字,大约阅读时间需要 9 分钟。

Linux 允许进程查询内核以获得其父进程的 PID,或者其任何子进程的执行状态。例如,进程可以创建一个子进程来执行特定的任务,然后调用诸如 wait() 这样的一些库函数检查子进程是否终止。如果子进程已经终止,那么,它的终止代号将告诉父进程这个任务是否已成功地完成。

为了遵循这些设计原则,不允许 Linux 内核在进程一终止后就丢弃包含在进程描述符字段中的数据。只有父进程发出了与被终止的进程相关的 wait() 类系统调用之后,才允许这样做。这就是引入僵死状态的原因:尽管从技术上来说进程已死,但必须保存它的描述符,直到父进程得到通知。
如果一个进程已经终止,但是它的父进程尚未调用 wait() 或 waitpid() 对它进行清理,这时的进程状态称为僵死状态,处于僵死状态的进程称为僵尸进程(zombie process)。任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了。

僵尸进程是如何产生的

为了观察到僵尸进程,我们自己写一个不正常的程序,父进程 fork 出子进程,子进程终止,而父进程既不终止也不调用 wait 清理子进程:

#include 
#include
#include
int main(void){ int i = 100; pid_t pid=fork(); if(pid < 0) { perror("fork failed."); exit(1); } if(pid > 0) { printf("This is the parent process. My PID is %d.\n", getpid()); for(; i > 0; i--) { sleep(1); } } else if(pid == 0) { printf("This is the child process. My PID is: %d. My PPID is: %d.\n", getpid(), getppid()); } return 0;}

把上面的代码保存到文件 zomprocdemo.c 文件中,并执行下面的命令编译:

$ gcc zomprocdemo.c -o zomprocdemo

然后运行编译出来的 zomprocdemo 程序:

$ ./zomprocdemo

此时子进程已经退出,但是父进程没有退出也没有通过 wait() 调用处理子进程。我们使用 ps 命令查看进程的状态:

上图红框中的大写字母 "Z" 说明 PID 为 112712 的进程此时处于僵死的状态。

让我们接着往下看!在结束 sleep 后父进程退出。当父进程退出后,子进程会变成孤儿进程,此时它会被一个管理进程收养。在不同的系统中,这个管理进程不太一样,早期一般是 init 进程,Ubuntu 上是 upstart,还有近来的 Systemd。但是它们都完成相同的任务,就是 wiat() 这些孤儿进程,并最终释放它们占用的系统进程表中的资源。这样,这些已经僵死的孤儿进程就彻底的被清除了。

僵尸进程的危害

在进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号 PID,退出状态 the termination status of the process,运行时间 the amount of CPU time taken by the process 等)。直到父进程通过 wait / waitpid 来取时才释放。

如果进程不调用 wait / waitpid 的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。

如何处理僵尸进程

僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要在父进程中通过 wait() 来避免僵尸进程的产生。

当系统中出现了僵尸进程时,我们是无法通过 kill 命令把它清除掉的。但是我们可以杀死它的父进程,让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。

下面的 demo 中,父进程通过 wait() 等待子进程结束:

#include 
#include
#include
#include
#include
int main(void){ pid_t pid; pid = fork(); if (pid < 0) { perror("fork failed"); exit(1); } if (pid == 0) { int i; for (i = 3; i > 0; i--) { printf("This is the child\n"); sleep(1); } // exit with code 3 for test. exit(3); } else { int stat_val; wait(&stat_val); if (WIFEXITED(stat_val)) { printf("Child exited with code %d\n", WEXITSTATUS(stat_val)); } } return 0;}

demo 中父进程不仅等待子进程结束,还通过 WEXITSTATUS 宏取到了子进程的 exit code。

本文转自sparkdev博客园博客,原文链接:http://www.cnblogs.com/sparkdev/p/8275221.html,如需转载请自行联系原作者

你可能感兴趣的文章
本地推送
查看>>
Beta 冲刺 (7/7)
查看>>
区块链实现简单的电商交易(以太坊)
查看>>
VMware报错:"激活连接失败:No suitable device found for this connection."
查看>>
maven设置
查看>>
个人考场VIM配置
查看>>
adobe
查看>>
微信小程序中的分享事件
查看>>
HDU 6069 Counting Divisors【区间素筛】【经典题】【好题】
查看>>
使用HAXM为QEMU for Windows加速
查看>>
配置tomcat下war包可以自压缩
查看>>
idea中artifacts、facets、modules是什么意思?
查看>>
大数据下的Distinct Count(一):序
查看>>
android 打包
查看>>
FUCKED-BUG之临时对象的生死
查看>>
一句话开启XP_CMDSHELL
查看>>
【100题】第四十五题 雅虎面试两道题(矩阵判断、数组划分)
查看>>
MySQL基础知识
查看>>
HTML页面优化
查看>>
centos6下安装docker
查看>>