何为僵尸进程?
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程
成为僵尸进程的因素
1. 子进程 先于 父进程退出;
2. 子进程的状态信息,没有被父进程回收;
那么问题来了,子进程退出了,父进程怎么知道呢?
对该机制有稍微了解的话,不难得知一个关键因素:SIGCHLD
。正是这个SIGCHLD
起到了通知的作用,所以后面的处理也是基于它而实现。
僵尸进程处理方案
1. 父进程捕获 SIGCHLD
信号,则显示调用 wait
或 waitpid
;
2. 父进程直接忽略该信号。signal(SIGCHLD, SIG_IGN)
,这样子进程直接会退出。 需要注意的是,虽然进程对于 `SIGCHLD`的默认动作是忽略,但是还是显示写出来,才能有效(不显示写出来无效);
3. 把父进程杀了,子进程直接过继给 init
,由 init
伺候着。 不用担心 init
会挂着一堆僵尸, init
本身的设计就有专门回收的处理,所以有多少回收多少;
事后处理
方法一: kill –18 PPID (PPID是其父进程)
这个信号是告诉父进程,该子进程已经死亡了,请收回分配给他的资源。
方法二:如果不行则看能否终止其父进程(如果其父进程不需要的话)。先看其父进程又无其他子进程,如果有,可能需要先kill其他子进程,也就是兄弟进程。方法是:
kill –15 PID1 PID2(PID1,PID2是僵尸进程的父进程的其它子进程)。
然后再kill父进程:kill –15 PPID
Z之所以杀不死,是因为它已经死了,否则怎么叫 Zombie(僵尸)呢?冤魂不散,自然是生前有结未解之故。
在UNIX/Linux中,每个进程都有一个父进程,进程号叫PID(Process ID),相应地,父进程号就叫PPID(Parent PID)。当进程死亡时,它会自动关闭已打开的文件,舍弃已占用的内存、交换空间等等系统资源,然后向其父进程返回一个退出状态值,报告死讯。如果程序有 bug,就会在这最后一步出问题。儿子说我死了,老子却没听见,没有及时收棺入殓,儿子便成了僵尸。在UNIX/Linux中消灭僵尸的手段比较残忍,执行 ps axjf 找出僵尸进程的父进程号(PPID,第一列),先杀其父,然后再由进程天子 init(其PID为1,PPID为0)来一起收拾父子僵尸,超度亡魂,往生极乐。
注意,子进程变成僵尸只是碍眼而已,并不碍事,如果僵尸的父进程当前有要务在身,则千万不可贸然杀之。
参考: