分类: Java
2008-04-26 08:35:39
在linux中你可能进程听到有僵尸进程,那么究竟什么是僵尸进程,他又是怎样产生的呢?下面我们通过1个例子来说明一下。
我们知道退出一个进程用系统调用exit, 但是这并不意味着该进程马上就消失了,事实上它还留下了一个被称为僵尸进程(Zombie)的数据结构。在Linux进程的5种状态中,僵尸进程是非常特 殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收 集,除此之外,僵尸进程不再占有任何内存空间。从这点来看,僵尸进程虽然有一个很酷的名字,但它的影响力远远抵不上那些真正的僵尸兄弟,真正的僵尸总能令 人感到恐怖,而僵尸进程却除了留下一些供人凭吊的信息,对系统毫无作用。
也许读者们还对这个新概念比较好奇,那就让我们来看一眼Linux里的僵尸进程究竟长什么样子。
当一个进程已退出,但其父进程还没有调用系统调用wait(稍后介绍)对其进行收集之前的这段时间里,它会一直保持僵尸状态,利用这个特点,我们来写一个简单的小程序:
在这个程序中有三个进程,主进程,新进程(父进程)和他的子进程。 主进程创建了新进程(父进程)之后立刻就退出了,他的资源会被init进程回收,现在只剩下了新进程(父进程)和它创建的子进程,而这个新进程(父进程) 创建的子进程输出了一些信息之后就立刻就退出了,就只剩下了新进程(父进程),可是这个父进程并没有调用wait来回收它创建的子进程(虽然此时他的子进 程已经退出了,但是仍在在进程表中占有一席之地,这个需要父进程用wait来回收),而此时此刻,这个父进程仍在死循环中(while(1);),于是他 的子进程便成为僵尸进程, 我们用 ps aux就可以看到下面的东西:
第2行的Z以及
此时的僵尸进程我们已经无法用kill将其杀掉,要想将其杀掉,有两个方法,一个是重启机器,另一个就是变通的方法,杀掉它的父进程,当我们杀掉了它的父
进程之后,这个僵尸的父进程就会变为init(所有的进程,当它的父进程被杀掉之后,它父进程的父进程就会接管它,以此类推,直到最后由init来接管
它),而init进程是一个系统进程,它每隔一段时间就会用wait来回收这些没有父母的僵尸进程。在这里,当你用kill
1923杀掉它的父进程之后,你再用ps 命令就看不到它了。
我们就linux的发展来看一看僵尸进程:我们知道,Linux和UNIX总有着剪不断理还乱的亲缘关系,僵尸进程的概念也是从UNIX上继承来 的,而UNIX的先驱们设计这个东西并非是因为闲来无聊想烦烦其他的程序员。僵尸进程中保存着很多对程序员和系统管理员非常重要的信息,首先,这个进程是 怎么死亡的?是正常退出呢,还是出现了错误,还是被其它进程强迫退出的?其次,这个进程占用的总系统CPU时间和总用户CPU时间分别是多少?发生页错误 的数目和收到信号的数目。这些信息都被存储在僵尸进程中,试想如果没有僵尸进程,进程一退出,所有与之相关的信息都立刻归于无形,而此时程序员或系统管理 员需要用到,就只好干瞪眼了。
那么,我们如何收集这些信息,并终结这些僵尸进程呢?就要靠我们下面要讲到的waitpid调用和wait调用。这两者的作用都是收集僵尸进程留下的信息,同时使这个进程彻底消失。
所以,防止僵尸进程的方法就是要记得调用系统调用wait及时的将其回收。如果你不及时回收,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多,最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。关于wait系统调用的详细介绍请看。