IT貓撲網(wǎng):您身邊最放心的安全下載站! 最新更新|軟件分類|軟件專題|手機(jī)版|論壇轉(zhuǎn)貼|軟件發(fā)布

您當(dāng)前所在位置: 首頁(yè)操作系統(tǒng)LINUX → Linux僵尸進(jìn)程產(chǎn)生及如何避免

Linux僵尸進(jìn)程產(chǎn)生及如何避免

時(shí)間:2015-06-28 00:00:00 來(lái)源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評(píng)論(0)

  在fork()/execve()過(guò)程中,假設(shè)子進(jìn)程結(jié)束時(shí)父進(jìn)程仍存在,而父進(jìn)程fork()之前既沒(méi)安裝SIGCHLD信號(hào)處理函數(shù)調(diào)用waitpid()等待子進(jìn)程結(jié)束,又沒(méi)有顯式忽略該信號(hào),則子進(jìn)程成為僵尸進(jìn)程,無(wú)法正常結(jié)束,此時(shí)即使是root身份kill-9也不能殺死僵尸進(jìn)程。補(bǔ)救辦法是殺死僵尸進(jìn)程的父進(jìn)程(僵尸進(jìn)程的父進(jìn)程必然存在),僵尸進(jìn)程成為"孤兒進(jìn)程",過(guò)繼給1號(hào)進(jìn)程init,init始終會(huì)負(fù)責(zé)清理僵尸進(jìn)程。

  僵尸進(jìn)程是指的父進(jìn)程已經(jīng)退出,而該進(jìn)程dead之后沒(méi)有進(jìn)程接受,就成為僵尸進(jìn)程.(zombie)進(jìn)程

  怎樣產(chǎn)生僵尸進(jìn)程的:

  一個(gè)進(jìn)程在調(diào)用exit命令結(jié)束自己的生命的時(shí)候,其實(shí)它并沒(méi)有真正的被銷毀,而是留下一個(gè)稱為僵尸進(jìn)程(Zombie)的數(shù)據(jù)結(jié)構(gòu)(系統(tǒng)調(diào)用exit,它的作用是使進(jìn)程退出,但也僅僅限于將一個(gè)正常的進(jìn)程變成一個(gè)僵尸進(jìn)程,并不能將其完全銷毀)。在Linux進(jìn)程的狀態(tài)中,僵尸進(jìn)程

  是非常特殊的一種,它已經(jīng)放棄了幾乎所有內(nèi)存空間,沒(méi)有任何可執(zhí)行代碼,也不能被調(diào)度,僅僅在進(jìn)程列表中保留一個(gè)位置,記載該進(jìn)程的退

  出狀態(tài)等信息供其他進(jìn)程收集,除此之外,僵尸進(jìn)程不再占有任何內(nèi)存空間。它需要它的父進(jìn)程來(lái)為它收尸,如果他的父進(jìn)程沒(méi)安裝SIGCHLD信

  號(hào)處理函數(shù)調(diào)用wait或waitpid()等待子進(jìn)程結(jié)束,又沒(méi)有顯式忽略該信號(hào),那么它就一直保持僵尸狀態(tài),如果這時(shí)父進(jìn)程結(jié)束了,那么init進(jìn)程自動(dòng)

  會(huì)接手這個(gè)子進(jìn)程,為它收尸,它還是能被清除的。但是如果如果父進(jìn)程是一個(gè)循環(huán),不會(huì)結(jié)束,那么子進(jìn)程就會(huì)一直保持僵尸狀態(tài),這就是為什么系統(tǒng)中有時(shí)會(huì)有很多的僵尸進(jìn)程。

  Linux系統(tǒng)對(duì)運(yùn)行的進(jìn)程數(shù)量有限制,如果產(chǎn)生過(guò)多的僵尸進(jìn)程占用了可用的進(jìn)程號(hào),將會(huì)導(dǎo)致新的進(jìn)程無(wú)法生成。這就是僵尸進(jìn)程對(duì)系統(tǒng)的最大危害。

  僵尸進(jìn)程實(shí)例:

  /*-----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);

  }

  會(huì)不停地產(chǎn)生僵死進(jìn)程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內(nèi)會(huì)不斷產(chǎn)生僵尸進(jìn)程,知道父進(jìn)程exit(0);

  如果在調(diào)用wait/waitpid來(lái)為子進(jìn)程收尸,就不會(huì)產(chǎn)生僵尸進(jìn)程了。

  PS:運(yùn)行例子,先gcc zombie1.c -o zombie編譯,然后運(yùn)行zombie;

  然后可以可用ps -ef來(lái)查看是否產(chǎn)生了僵尸進(jìn)程。

  怎么查看僵尸進(jìn)程:

  利用命令ps,可以看到有標(biāo)記為Z的進(jìn)程就是僵尸進(jìn)程。

  怎樣來(lái)清除僵尸進(jìn)程:

  1.改寫父進(jìn)程,在子進(jìn)程死后要為它收尸。具體做法是接管SIGCHLD信號(hào)。子進(jìn)程死后,會(huì)發(fā)送SIGCHLD信號(hào)給父進(jìn)程,父進(jìn)程收到此信號(hào)后,執(zhí)行 waitpid()函數(shù)為子進(jìn)程收尸。這是基于這樣的原理:就算父進(jìn)程沒(méi)有調(diào)用wait,內(nèi)核也會(huì)向它發(fā)送SIGCHLD消息,盡管對(duì)的默認(rèn)處理是忽略,如果想響應(yīng)這個(gè)消息,可以設(shè)置一個(gè)處理函數(shù)。

  2.把父進(jìn)程殺掉。父進(jìn)程死后,僵尸進(jìn)程成為"孤兒進(jìn)程",過(guò)繼給1號(hào)進(jìn)程init,init始終會(huì)負(fù)責(zé)清理僵尸進(jìn)程.它產(chǎn)生的所有僵尸進(jìn)程也跟著消失。

  在Linux中可以用

  ps auwx

  發(fā)現(xiàn)僵尸進(jìn)程

  a all w/ tty, including other users 所有窗口和終端,包括其他用戶的進(jìn)程

  u user-oriented 面向用戶(用戶友好)

  -w,w wide output 寬格式輸出

  x processes w/o controlling ttys

  在僵尸進(jìn)程后面 會(huì)標(biāo)注

  ps axf

  看進(jìn)程樹,以樹形方式現(xiàn)實(shí)進(jìn)程列表

  ps axm

  會(huì)把線程列出來(lái),在linux下進(jìn)程和線程是統(tǒng)一的,是輕量級(jí)進(jìn)程的兩種方式。

  ps axu

  顯示進(jìn)程的詳細(xì)狀態(tài)

  ===========================================

  killall

  kill -15

  kill -9

  一般都不能殺掉 defunct進(jìn)程

  用了kill -15,kill -9以后 之后反而會(huì)多出更多的僵尸進(jìn)程

  kill -kill pid

  fuser -k pid

  可以考慮殺死他的parent process,

  kill -9 他的parent process

  =========================================== 一個(gè)已經(jīng)終止,但是其父進(jìn)程尚未對(duì)其進(jìn)行善后處理(獲取終止子進(jìn)程的有關(guān)信息、釋放它仍占用的資源)的進(jìn)程被稱為僵死進(jìn)程(Zombie Process)。

  避免zombie的方法:

  1)在SVR4中,如果調(diào)用signal或sigset將SIGCHLD的配置設(shè)置為忽略,則不會(huì)產(chǎn)生僵死子進(jìn)程。另外,使用SVR4版的 sigaction,則可設(shè)置SA_NOCLDWAIT標(biāo)志以避免子進(jìn)程僵死。

  Linux中也可使用這個(gè),在一個(gè)程序的開始調(diào)用這個(gè)函數(shù)

  signal(SIGCHLD,SIG_IGN);

  2)調(diào)用fork兩次。程序8 - 5 實(shí)現(xiàn)了這一點(diǎn)。

  3)用waitpid等待子進(jìn)程返回.

  ===========================================

  zombie進(jìn)程是僵死進(jìn)程。防止它的辦法,一是用wait,waitpid之類的函數(shù)獲得

  進(jìn)程的終止?fàn)顟B(tài),以釋放資源。另一個(gè)是fork兩次

  ===========================================

  defunct進(jìn)程只是在process table里還有一個(gè)記錄,其他的資源沒(méi)有占用,除非你的系統(tǒng)的process個(gè)數(shù)的限制已經(jīng)快超過(guò)了,zombie進(jìn)程不會(huì)有更多的壞處。

  可能唯一的方法就是reboot系統(tǒng)可以消除zombie進(jìn)程。

  ===========================================

  任何程序都有僵尸狀態(tài),它占用一點(diǎn)內(nèi)存資源(也就是進(jìn)程表里還有一個(gè)記錄),僅僅是表象而已不必害怕。如果程序有問(wèn)題有機(jī)會(huì)遇見(jiàn),解決大批量僵尸簡(jiǎn)單有效的辦法是重起。kill是無(wú)任何效果的

  fork與zombie/defunct"

  在Unix下的一些進(jìn)程的運(yùn)作方式。當(dāng)一個(gè)進(jìn)程死亡時(shí),它并不是完全的消失了。進(jìn)程終止,它不再運(yùn)行,但是還有一些殘留的小東西等待父進(jìn)程收回。這些殘留的東西包括子進(jìn)程的返回值和其他的一些東西。當(dāng)父進(jìn)程 fork()一個(gè)子進(jìn)程后,它必須用 wait() 或者 waitpid() 等待子進(jìn)程退出。正是這個(gè) wait() 動(dòng)作來(lái)讓子進(jìn)程的殘留物消失。

  自然的,在上述規(guī)則之外有個(gè)例外:父進(jìn)程可以忽略 SIGCLD 軟中斷而不必要 wait()。可以這樣做到(在支持它的系統(tǒng)上,比如Linux):

  main()

  {

  signal(SIGCLD, SIG_IGN); /* now I don't have to wait()! */

  .

  .

  fork();

  fork();

  fork(); /* Rabbits, rabbits, rabbits! */

 ?。?/p>

  現(xiàn)在,子進(jìn)程死亡時(shí)父進(jìn)程沒(méi)有 wait(),通常用 ps 可以看到它被顯示為""。它將永遠(yuǎn)保持這樣 直到 父進(jìn)程 wait(),或者按以下方法處理。

  這里是你必須知道的另一個(gè)規(guī)則:當(dāng)父進(jìn)程在它wait()子進(jìn)程之前死亡了(假定它沒(méi)有忽略 SIGCLD),子進(jìn)程將把 init(pid1)進(jìn)程作為它的父進(jìn)程。如果子進(jìn)程工作得很好并能夠控制,這并不是問(wèn)題。但如果子進(jìn)程已經(jīng)是defunct,我們就有了一點(diǎn)小麻煩???,原先的父進(jìn)程不可能再 wait(),因?yàn)樗呀?jīng)消亡了。這樣,init 怎么知道 wait() 這些zombie 進(jìn)程。

  答案:不可預(yù)料的。在一些系統(tǒng)上,init周期性的破壞掉它所有的defunct進(jìn)程。在另外一些系統(tǒng)中,它干脆拒絕成為任何defunct進(jìn)程的父進(jìn)程,而是馬上毀滅它們。如果你使用上述系統(tǒng)的一種,可以寫一個(gè)簡(jiǎn)單的循環(huán),用屬于init的defunct進(jìn)程填滿進(jìn)程表。這大概不會(huì)令你的系統(tǒng)管理員很高興吧?

  你的任務(wù):確定你的父進(jìn)程不要忽略 SIGCLD,也不要 wait() 它 fork() 的所有進(jìn)程。不過(guò),你也未必 要總是這樣做(比如,你要起一個(gè) daemon 或是別的什么東西),但是你必須小心編程,如果你是一個(gè) fork()的新手。另外,也不要在心理上有任何束縛。

  總結(jié):

  子進(jìn)程成為 defunct 直到父進(jìn)程 wait(),除非父進(jìn)程忽略了 SIGCLD 。

  更進(jìn)一步,父進(jìn)程沒(méi)有 wait() 就消亡(仍假設(shè)父進(jìn)程沒(méi)有忽略 SIGCLD )的子進(jìn)程(活動(dòng)的或者 defunct)成為 init 的子進(jìn)程,init 用重手法處理它們。

關(guān)鍵詞標(biāo)簽:Linux,僵尸進(jìn)程

相關(guān)閱讀

文章評(píng)論
發(fā)表評(píng)論

熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP Linux操作系統(tǒng)修改IP

相關(guān)下載

    人氣排行 Linux下獲取CPUID、硬盤序列號(hào)與MAC地址 dmidecode命令查看內(nèi)存型號(hào) linux tc實(shí)現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關(guān)機(jī)、重啟、注銷 命令 查看linux服務(wù)器硬盤IO讀寫負(fù)載