谈谈守护进程与僵尸进程


维护的第一个商业服务就用了两次fork产生守护进程的做法,前两天在网上看到许多帖子以及一些unix书籍,认为一次fork后产生守护进程足够了,各有道理吧,不过多了一次fork到底是出于什么目的呢?


进程也就是task,看看内核里维护进程的数据结构task_struct,这里有两个成员:

[cpp]
  1. struct task_struct {  
  2.     volatile long state;  
  3.     int exit_state;  
  4.     ...  
  5. }  
看看include/linux/sched.h里的value取值:

[cpp]
  1. #define TASK_RUNNING        0   
  2. #define TASK_INTERRUPTIBLE  1   
  3. #define TASK_UNINTERRUPTIBLE    2   
  4. #define __TASK_STOPPED      4   
  5. #define __TASK_TRACED       8   
  6. /* in tsk->exit_state */  
  7. #define EXIT_ZOMBIE     16   
  8. #define EXIT_DEAD       32   
  9. /* in tsk->state again */  
  10. #define TASK_DEAD       64   
  11. #define TASK_WAKEKILL       128   
  12. #define TASK_WAKING     256   
  13. #define TASK_STATE_MAX      512  
可以看到,进程状态里除了大家都理解的running/interuptible/uninterruptible/stop等状态外,还有一个ZOMBIE状态,这个状态是怎么回事呢?


这是因为linux里的进程都属于一颗树,树的根结点是linux系统初始化结束阶段时启动的init进程,这个进程的pid是1,所有的其他进程都是它的子孙。除了init,任何进程一定有他的父进程,而父进程会负责分配(fork)、回收(wait4)它申请的进程资源。这个树状关系也比较健壮,当某个进程还在运行时,它的父进程却退出了,这个进程却没有成为孤儿进程,因为linux有一个机制,init进程会接管它,成为它的父进程。这也是守护进程的由来了,因为守护进程的其中一个要求就是希望init成为守护进程的父进程。


如果某个进程自身终止了,在调用exit清理完相关的内容文件等资源后,它就会进入ZOMBIE状态,它的父进程会调用wait4来回收这个task_struct,但是,如果父进程一直没有调用wait4去释放子进程的task_struct,问题就来了,这个task_struct谁来回收呢?永远没有人,除非父进程终止后,被init进程接管这个ZOMBIE进程,然后调用wait4来回收进程描述符。如果父进程一直在运行着,这个ZOMBIE会永远的占用系统资源,用KILL发任何信号量也不能释放它。这是很可怕的,因为服务器上可能会出现无数ZOMBIE进程导致机器挂掉。

  • 1
  • 2
  • 下一页

相关内容