歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux僵屍進程產生及如何避免

Linux僵屍進程產生及如何避免

日期:2017/2/25 10:37:44   编辑:Linux教程

在fork()/execve()過程中,假設子進程結束時父進程仍存在,而父進程fork()之前既沒安裝SIGCHLD信號處理函數調用waitpid()等待子進程結束,又沒有顯式忽略該信號,則子進程成為僵屍進程,無法正常結束,此時即使是root身份kill-9也不能殺死僵屍進程。補救辦法是殺死僵屍進程的父進程(僵屍進程的父進程必然存在),僵屍進程成為"孤兒進程",過繼給1號進程init,init始終會負責清理僵屍進程。

  僵屍進程是指的父進程已經退出,而該進程dead之後沒有進程接受,就成為僵屍進程.(zombie)進程

  怎樣產生僵屍進程的:

  一個進程在調用exit命令結束自己的生命的時候,其實它並沒有真正的被銷毀,而是留下一個稱為僵屍進程(Zombie)的數據結構(系統調用exit,它的作用是使進程退出,但也僅僅限於將一個正常的進程變成一個僵屍進程,並不能將其完全銷毀)。在Linux進程的狀態中,僵屍進程

  是非常特殊的一種,它已經放棄了幾乎所有內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退

  出狀態等信息供其他進程收集,除此之外,僵屍進程不再占有任何內存空間。它需要它的父進程來為它收屍,如果他的父進程沒安裝SIGCHLD信

  號處理函數調用wait或waitpid()等待子進程結束,又沒有顯式忽略該信號,那麼它就一直保持僵屍狀態,如果這時父進程結束了,那麼init進程自動

  會接手這個子進程,為它收屍,它還是能被清除的。但是如果如果父進程是一個循環,不會結束,那麼子進程就會一直保持僵屍狀態,這就是為什麼系統中有時會有很多的僵屍進程。

  Linux系統對運行的進程數量有限制,如果產生過多的僵屍進程占用了可用的進程號,將會導致新的進程無法生成。這就是僵屍進程對系統的最大危害。

  僵屍進程實例:

  /*-----zombie1.c-----*/

  #include "sys/types.h"

  #include "sys/wait.h"

  #include "stdio.h"

  #include "unistd.h"

  int main(int argc, char* argv[])

  {

  while(1)

  {

  pid_t chi = fork();

  if(chi == 0)

  {

  execl("/bin/bash","bash","-c","ls",NULL);

  }

  sleep(2);

  }

  會不停地產生僵死進程ls;

  /*-----zombie2.c-----*/

  #include

  #include

  main()

  {

  if(!fork())

  {

  printf("child pid=%d\n", getpid());

  exit(0);

  }

  /*wait();*/

  /*waitpid(-1,NULL,0);*/

  sleep(60);

  printf("parent pid=%d \n", getpid());

  exit(0);

  }

  60s內會不斷產生僵屍進程,知道父進程exit(0);

  如果在調用wait/waitpid來為子進程收屍,就不會產生僵屍進程了。

  PS:運行例子,先gcc zombie1.c -o zombie編譯,然後運行zombie;

  然後可以可用ps -ef來查看是否產生了僵屍進程。

  怎麼查看僵屍進程:

  利用命令ps,可以看到有標記為Z的進程就是僵屍進程。

  怎樣來清除僵屍進程:

  1.改寫父進程,在子進程死後要為它收屍。具體做法是接管SIGCHLD信號。子進程死後,會發送SIGCHLD信號給父進程,父進程收到此信號後,執行 waitpid()函數為子進程收屍。這是基於這樣的原理:就算父進程沒有調用wait,內核也會向它發送SIGCHLD消息,盡管對的默認處理是忽略,如果想響應這個消息,可以設置一個處理函數。

  2.把父進程殺掉。父進程死後,僵屍進程成為"孤兒進程",過繼給1號進程init,init始終會負責清理僵屍進程.它產生的所有僵屍進程也跟著消失。

Copyright © Linux教程網 All Rights Reserved