久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

linux僵尸進程怎么避免

170次閱讀
沒有評論

共計 4268 個字符,預計需要花費 11 分鐘才能閱讀完成。

本文丸趣 TV 小編為大家詳細介紹“linux 僵尸進程怎么避免”,內容詳細,步驟清晰,細節處理妥當,希望這篇“linux 僵尸進程怎么避免”文章能幫助大家解決疑惑,下面跟著丸趣 TV 小編的思路慢慢深入,一起來學習新知識吧。

linux 僵尸進程是一個早已死亡的進程,但是在進程表中仍占了一個位置;如果子進程死亡時父進程沒有 wait(),通常用 ps 可以看到它被顯示為“”,這樣就產生了僵尸進程;如果大量產生僵尸進程,那么將因為沒有可用的進程號而導致系統不能產生新的進程,所以要避免有僵尸進程。

一、什么是僵尸進程

在 UNIX 系統中,一個進程結束了,但是他的父進程沒有等待 (調用 wait / waitpid) 他,那么他將變成一個僵尸進程。當用 ps 命令觀察進程的執行狀態時,看到這些進程的狀態欄為 defunct。僵尸進程是一個早已死亡的進程,但在進程表(processs table)中仍占了一個位置(slot)。

但是如果該進程的父進程已經先結束了,那么該進程就不會變成僵尸進程。因為每個進程結束的時候, 系統都會掃描當前系統中所運行的所有進程,看看有沒有哪個進程是剛剛結束的這個進程的子進程,如果是的話,就由 Init 進程來接管他,成為他的父進程,從而保證每個進程都會有一個父進程。而 Init 進程會自動 wait 其子進程, 因此被 Init 接管的所有進程都不會變成僵尸進程。

二、UNIX 下進程的運作方式

每個 Unix 進程在進程表里都有一個進入點(entry),核心進程執行該進程時使用到的一切信息都存儲在進入點。當用 ps 命令察看系統中的進程信息時,看到的就是進程表中的相關數據。當以 fork()系統調用建立一個新的進程后,核心進程就會在進程表中給這個新進程分配一個進入點,然后將相關信息存儲在該進入點所對應的進程表內。這些信息中有一項是其父進程的識別碼。

子進程的結束和父進程的運行是一個異步過程,即父進程永遠無法預測子進程到底什么時候結束。那么會不會因為父進程太忙來不及 wait 子進程,或者說不知道子進程什么時候結束,而丟失子進程結束時的狀態信息呢?

不會。因為 UNIX 提供了一種機制可以保證,只要父進程想知道子進程結束時的狀態信息,就可以得到。這種機制就是:當子進程走完了自己的生命周期后,它會執行 exit()系統調用,內核釋放該進程所有的資源,包括打開的文件,占用的內存等。但是仍然為其保留一定的信息(包括進程號 the process ID,退出碼 exit code,退出狀態 the terminationstatus of the process,運行時間 the amount of CPU time taken by the process 等),這些數據會一直保留到系統將它傳遞給它的父進程為止,直到父進程通過 wait / waitpid 來取時才釋放。

也就是說,當一個進程死亡時,它并不是完全的消失了。進程終止,它不再運行,但是還有一些殘留的數據等待父進程收回。當父進程 fork() 一個子進程后,它必須用 wait()(或者 waitpid())等待子進程退出。正是這個 wait() 動作來讓子進程的殘留數據消失。

三、僵尸進程的危害

如果父進程不調用 wait / waitpid 的話,那么保留的那段信息就不會釋放,其進程號就會一直被占用,但是系統的進程表容量是有限的,所能使用的進程號也是有限的,如果大量的產生僵尸進程, 將因為沒有可用的進程號而導致系統不能產生新的進程。

所以,defunct 進程不僅占用系統的內存資源,影響系統的性能,而且如果其數目太多,還會導致系統癱瘓。而且,由于調度程序無法選中 Defunct 進程,所以不能用 kill 命令刪除 Defunct 進程,惟一的方法只有重啟系統。

四、僵尸進程的產生

如果子進程死亡時父進程沒有 wait(),通常用 ps 可以看到它被顯示為“defunct”,這樣就產生了僵尸進程。它將永遠保持這樣直到父進程 wait()。

由此可見,defunct 進程的出現時間是在子進程終止后,但是父進程尚未讀取這些數據之前。利用這一點我們可以用下面的程序建立一個 defunct 進程:

#include stdio.h 

#include sys/types.h

main()  


if(!fork())  
   { 

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

       exit(0);  

   }  

   sleep(20);  

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

   exit(0);  

}

當上述程序以后臺的方式執行時,第 17 行強迫程序睡眠 20 秒,讓用戶有時間輸入 ps - e 指令,觀察進程的狀態,我們看到進程表中出現了 defunct 進程。當父進程執行終止后,再用 ps - e 命令觀察時,我們會發現 defunct 進程也隨之消失。這是因為父進程終止后,init 進程會接管父進程留下的這些“孤兒進程”(orphan process),而這些“孤兒進程”執行完后,它在進程表中的進入點將被刪除。如果一個程序設計上有缺陷,就可能導致某個進程的父進程一直處于睡眠狀態或是陷入死循環,父進程沒有 wait 子進程,也沒有終止以使 Init 接管,該子進程執行結束后就變成了 defunct 進程,這個 defunct 進程可能會一直留在系統中直到系統重新啟動。

在看一個產生僵尸進程的例子。

子進程要執行的程序 test_prog

//test.c 
#include stdio.h int main()  {  
int i = 0;  
for (i = 0 ; i i++)  
       { 
               printf (child time %d\n , i+1);  
               sleep (1);  
       }  
return 0;  }

父進程 father 的代碼 father.c

#include  stdio.h  
#include  unistd.h  
#include  sys/types.h  
#include  sys/wait.h  
int main() 
{ 
 int pid = fork (); 
 if (pid == 0) 
 { 
 system ( ./test_prog  
 _exit (0); 
 }else 
 { 
 int i = 0; 
 /* 
 int status = 0; 
 while (!waitpid(pid,  status, WNOHANG)) 
 { 
 printf (father waiting%d\n , ++i); 
 sleep (1); 
 }*/ 
 while (1) 
 { 
 printf (father waiting over%d\n , ++i); 
 sleep (1); 
 } 
 return 0; 
 } 
 
}

執行./father, 當子進程退出后,由于父進程沒有對它的退出進行關注,會出現僵尸進程

20786 pts/0    00:00:00 father  
20787 pts/0    00:00:00 father defunct

總結:子進程成為 defunct 直到父進程 wait(),除非父進程忽略了 SIGCLD。更進一步,父進程沒有 wait() 就消亡(仍假設父進程沒有忽略 SIGCLD)的子進程(活動的或者 defunct)成為 init 的子進程,init 著手處理它們。

五、如何避免僵尸進程

1、父進程通過 wait 和 waitpid 等函數等待子進程結束,這會導致父進程掛起。

在上個例子中,如果我們略作修改,在第 8 行 sleep()系統調用前執行 wait()或 waitpid()系統調用,則子進程在終止后會立即把它在進程表中的數據返回給父進程,此時系統會立即刪除該進入點。在這種情形下就不會產生 defunct 進程。

2. 如果父進程很忙,那么可以用 signal 函數為 SIGCHLD 安裝 handler。在子進程結束后,父進程會收到該信號,可以在 handler 中調用 wait 回收。

3. 如果父進程不關心子進程什么時候結束,那么可以用 signal(SIGCLD, SIG_IGN)或 signal(SIGCHLD, SIG_IGN)通知內核,自己對子進程的結束不感興趣,那么子進程結束后,內核會回收,并不再給父進程發送信號

4. fork 兩次,父進程 fork 一個子進程,然后繼續工作,子進程 fork 一個孫進程后退出,那么孫進程被 init 接管,孫進程結束后,init 會回收。不過子進程的回收還要自己做。下面就是 Stevens 給的采用兩次 folk 避免僵尸進程的示例:

#include apue.h #include sys/wait.h  int main(void)  ...{ 
    pid_t    pid;  

if ((pid = fork()) 0) ...{ 
        err_sys(fork error  
    } else if (pid == 0) ...{    /**//* first child */
if ((pid = fork()) 0)  
            err_sys(fork error  
else if (pid 0)  
            exit(0);    /**//* parent from second fork == first child */
/**//*
         * We re the second child; our parent becomes init as soon
         * as our real parent calls exit() in the statement above.
         * Here s where we d continue executing, knowing that when
         * we re done, init will reap our status.
        */
        sleep(2);  
        printf(second child, parent pid = %d , getppid());  
        exit(0);  
    }  

if (waitpid(pid, NULL, 0) != pid)  /**//* wait for first child */
        err_sys(waitpid error  

/**//*
     * We re the parent (the original process); we continue executing,
     * knowing that we re not the parent of the second child.
    */
    exit(0);  }

讀到這里,這篇“linux 僵尸進程怎么避免”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注丸趣 TV 行業資訊頻道。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-12發表,共計4268字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 庆元县| 田林县| 鸡西市| 吉安县| 平利县| 中阳县| 巴东县| 乐陵市| 封丘县| 馆陶县| 得荣县| 舒城县| 湖州市| 城市| 南昌市| 咸阳市| 博乐市| 宝应县| 平塘县| 东乡县| 云阳县| 漾濞| 永年县| 哈巴河县| 五华县| 江达县| 龙胜| 邵武市| 襄樊市| 柘荣县| 彰武县| 顺平县| 平和县| 保亭| 东兴市| 光山县| 霍城县| 界首市| 辛集市| 买车| 兴业县|