Linux僵尸进程产生原因及解决方法

  

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

  

为了遵循这些设计原则,不允许Linux内核在进程一终止后就丢弃包含在进程描述符字段中的数据,只有父进程发出了与被终止的进程相关的等待()类系统调用之后,才允许这样做。这就是引入僵死状态的原因,尽管从技术上来说进程已死,但必须保存它的描述符,直到父进程得到通知。
  

  

如果一个进程已经终止,但是它的父进程尚未调用等()或waitpid()对它进行清理,这时的进程状态称为僵死状态,处于僵死状态的进程称为僵尸进程(僵尸进程)。任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了。

  

<强>僵尸进程是如何产生的

  

,在UNIX系统中,一个进程结束了,但是他的父进程没有等待(调用等待/waitpid)他,那么他将变成一个僵尸进程。通过ps命令查看其带有废弃的标志。僵尸进程是一个早已死亡的进程,但在进程表(流程表)中仍占了一个位置(槽)。
  

  

但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程。因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而Init进程会自动等待其子进程,因此被Init接管的所有进程都不会变成僵尸进程。

  

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

        # include & lt; unistd.h>   # include & lt; stdio.h>   # include & lt; stdlib.h>      int主要(空白)   {   int i=100;   pid_t pid=fork ();   如果(pid & lt;0)   {   perror(“叉失败。”);   退出(1);   }   如果(pid比;0)   {   printf("这是父进程。我的PID % d。\ n”, getpid ());   (;我在;0;我——)   {   睡眠(1);   }   }   else if (pid==0)   {   printf(“这是子进程。我的PID是:% d。我的PPID是:% d。\ n”, getpid (), getppid ());   }   返回0;   }      

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

        gcc zomprocdemo美元。c - o zomprocdemo      

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

        美元。/zomprocdemo      

癓inux僵尸进程产生原因及解决方法"

  

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

  

癓inux僵尸进程产生原因及解决方法"

  

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

  

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

  

<强>僵尸进程的危害

  

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

  

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

  

<>强如何处理僵尸进程

  

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

Linux僵尸进程产生原因及解决方法