性能文章>僵尸进程的成因以及僵尸可以被“杀死”吗?>

僵尸进程的成因以及僵尸可以被“杀死”吗?原创

555404

僵尸不可能被杀死,因为它已经死了,不存在再死一次的问题。死的对立面是活,死者已死。只有活的进程才可能被杀死

什么是僵尸

首先要明确一点,僵尸进程的含义是:子进程已经死了,但是父进程还没有wait它的一个中间状态,这个时候子进程是一个僵尸。正常情况下子死,父wait,清理掉子进程的task_struct,释放子进程的PID:

image.png

编译上述程序,运行,我们看到2个a.out进程:

image.png

杀死子进程4578,看到父进程的打印:

image.png

之后,4578会消失,因为父进程执行到了wait,也知道了子进程是被信号2杀掉的。

但是如果子进程死了,父进程不执行到wait,比如把上图中的"#if 0"改为"#if 1",杀死子进程后,子进程就会是一个僵尸:

image.png

我们重新运行,当我们用kill -2杀掉子进程4628后,我们发现4628成为一个僵尸,状态变为Z+,名字上也加了一个棺材[],成为[a.out]:

image.png

僵尸不可能被杀死

我们看到上面4628是个僵尸很不爽,所以我们想把它干掉,据说Linux有个信号9,神挡杀神,佛挡杀佛,我们现在来用kill -9干掉4628:

image.png

从上图可以看出,我们把4628用kill -9捅了好多刀,但是最后看4628这个僵尸,还是没有消失。

因为僵尸已经是死了,它不可能再次被杀死,你给它捅一万刀,它也是个死人,不可能再次死!

僵尸不可能被杀死,因为它已经死了!只等父进程来wait清理尸体了。

这个时候我们能够把僵尸消失掉的方法,就是杀死僵尸进程的父进程4627

一个僵尸可以被杀死的假象

下面的这个程序证明“僵尸可以被杀死”:

image.png

我们在主线程里面,pthread_create()创建线程后,pthread_exit()退出,这个时候我们会发现,在ps命令里面,a.out显示为一个僵尸:

image.png

这个时候我们来杀死4730这个僵尸:

kill -9 4730

我们会惊奇地发现,4730真地会从ps命令里面消失!

image.png

我们把时间轴拉回调用"kill -9 4730"之前。刚才我们“看起来”能杀死僵尸的本质原因是,当主线程4730调用pthread_exit()退出后,主线程4730的状态确实是僵尸了,但是该进程里面的4731线程,却没有死:

image.png

image.png

看看4731:

image.png

4731是活着的,证明整个进程并没有挂。所以4730的退出,只是让整个进程半死。而由于ps这些命令的误会,4730凑巧又是整个进程的PID,它显示地好像整个4370成了僵尸一样。

image.png

那么,根据POSIX标准关于信号(signal)的定义,当我们执行kill -9 4730(4730是4730和4731的TGID,也是整个进程用户态视角的PID)的时候,是要杀死整个4730进程的,所以这个时候4731被我们杀死,整个进程就都死了,这个时候,执行到父进程的wait逻辑,导致僵尸消失。

所以,在本例中,kill -9 4730看起来是"杀死了僵尸”,实际是杀死了4730整个进程(里面的每个线程),导致整个进程死。在次之前,整个进程实际还是活的。

文章来自公众号:Linux阅码场,作者:宋宝华

请先登录,再评论

暂无回复,快来写下第一个回复吧~

为你推荐

在调试器里看LINUX内核态栈溢出
图灵最先发明了栈,但没有给它取名字。德国人鲍尔也“发明”了栈,取名叫酒窖。澳大利亚人汉布林也“发明”了栈,取名叫弹夹。1959年,戴克斯特拉在度假时想到了Stack这个名字,后来被广泛使用。
LONG究竟有多长,从皇帝的新衣到海康SDK
转眼之间初中毕业30年了,但我仍清楚的记得初中英语的一篇课文,题目叫《皇帝的新装》(“The king’s new clothes”)。这篇课文的前两句话是:”Long long ago, there
雕刻在LINUX内核中的LINUS故事
因为LINUX操作系统的流行,Linus 已经成为地球人都知道的名人。虽然大家可能都听过钱钟书先生的名言:“假如你吃个鸡蛋觉得味道不错,又何必认识那个下蛋的母鸡呢?” 但是如果真是遇到一个“特别显赫”
如何使用Linux内核中没有被导出的变量或函数?
本文详细介绍了使用EXPORT_SYMBOL宏导出函数或变量、使用kallsyms_lookup_name()查找函数或变量的虚拟地址以及内核模块中直接使用内核函数的虚拟地址等3种方案解决没有被EXPORT_SYMBOL 相关的宏导出的变量或函数不能直接使用的问题
LINUX网络子系统中DMA机制的实现
我们先从计算机组成原理的层面介绍DMA,再简单介绍Linux网络子系统的DMA机制是如何的实现的。 计算机组成原理中的DMA 以往的I/O设备和主存交换信息都要经过CPU的操作。不论是最早的轮询方式,
一次 Docker 容器内大量僵尸进程排查分析
前段时间线上的一个使用 Google Puppeteer 生成图片的服务炸了,每个 docker 容器内都有几千个孤儿僵死进程没有回收,如下图所示。这篇文章比较长,主要就讲了下面这几个问题。- 什么情
内存泄漏(增长)火焰图
本文总结了在分析内存增长和内存泄漏问题用到的4种追踪方法得到有关内存使用情况的代码路径,使用栈追踪技术对代码路径进行检查,并且会以火焰图的形式把它们可视化输出,在Linux上演示分析过程,随后概述其它系统的情况。
为什么容器内存占用居高不下,频频 OOM(续)
在之前的文章《[为什么容器内存占用居高不下,频频 OOM](https://heapdump.cn/article/1589003)》 中,我根据现状进行了分析和说明,收到了很多读者的建议和疑