僵尸進(jìn)程/孤兒進(jìn)程

參考博客http://www.cnblogs.com/Anker/p/3271773.html

一:僵尸進(jìn)程(有害

進(jìn)程:一個(gè)進(jìn)程使用fork創(chuàng)建子進(jìn)程,如果子進(jìn)程退出,而父進(jìn)程并沒(méi)有調(diào)用wait或waitpid獲取子進(jìn)程的狀態(tài)信息,那么子進(jìn)程的進(jìn)程描述符仍然保存在系統(tǒng)中。這種進(jìn)程稱(chēng)之為僵死進(jìn)程。詳解如下:
們知道在unix/linux中,正常情況下子進(jìn)程是通過(guò)父進(jìn)程創(chuàng)建的,子進(jìn)程在創(chuàng)建新的進(jìn)程。子進(jìn)程的結(jié)束和父進(jìn)程的運(yùn)行是一個(gè)異步過(guò)程,即父進(jìn)程永遠(yuǎn)無(wú)法預(yù)測(cè)子進(jìn)程到底什么時(shí)候結(jié)束,如果子進(jìn)程一結(jié)束就立刻回收其全部資源,那么在父進(jìn)程內(nèi)將無(wú)法獲取子進(jìn)程的狀態(tài)信息。
因此,UNⅨ提供了一種機(jī)制可以保證父進(jìn)程可以在任意時(shí)刻獲取子進(jìn)程結(jié)束時(shí)的狀態(tài)信息:
1、在每個(gè)進(jìn)程退出的時(shí)候,內(nèi)核釋放該進(jìn)程所有的資源,包括打開(kāi)的文件,占用的內(nèi)存等。但是仍然為其保留一定的信息(包括進(jìn)程號(hào)the process ID,退出狀態(tài)the termination status of the process,運(yùn)行時(shí)間the amount of CPU time taken by the process等)
2、直到父進(jìn)程通過(guò)wait / waitpid來(lái)取時(shí)才釋放. 但這樣就導(dǎo)致了問(wèn)題,如果進(jìn)程不調(diào)用wait / waitpid的話,那么保留的那段信息就不會(huì)釋放,其進(jìn)程號(hào)就會(huì)一直被占用,但是系統(tǒng)所能使用的進(jìn)程號(hào)是有限的,如果大量的產(chǎn)生僵死進(jìn)程,將因?yàn)闆](méi)有可用的進(jìn)程號(hào)而導(dǎo)致系統(tǒng)不能產(chǎn)生新的進(jìn)程. 此即為僵尸進(jìn)程的危害,應(yīng)當(dāng)避免。
  任何一個(gè)子進(jìn)程(init除外)在exit()之后,并非馬上就消失掉,而是留下一個(gè)稱(chēng)為僵尸進(jìn)程(Zombie)的數(shù)據(jù)結(jié)構(gòu),等待父進(jìn)程處理。這是每個(gè)子進(jìn)程在結(jié)束時(shí)都要經(jīng)過(guò)的階段。如果子進(jìn)程在exit()之后,父進(jìn)程沒(méi)有來(lái)得及處理,這時(shí)用ps命令就能看到子進(jìn)程的狀態(tài)是“Z”。如果父進(jìn)程能及時(shí) 處理,可能用ps命令就來(lái)不及看到子進(jìn)程的僵尸狀態(tài),但這并不等于子進(jìn)程不經(jīng)過(guò)僵尸狀態(tài)。 如果父進(jìn)程在子進(jìn)程結(jié)束之前退出,則子進(jìn)程將由init接管。init將會(huì)以父進(jìn)程的身份對(duì)僵尸狀態(tài)的子進(jìn)程進(jìn)行處理。

二:孤兒進(jìn)程(無(wú)害)

孤兒進(jìn)程:一個(gè)父進(jìn)程退出,而它的一個(gè)或多個(gè)子進(jìn)程還在運(yùn)行,那么那些子進(jìn)程將成為孤兒進(jìn)程。孤兒進(jìn)程將被init進(jìn)程(進(jìn)程號(hào)為1)所收養(yǎng),并由init進(jìn)程對(duì)它們完成狀態(tài)收集工作。
  孤兒進(jìn)程是沒(méi)有父進(jìn)程的進(jìn)程,孤兒進(jìn)程這個(gè)重任就落到了init進(jìn)程身上,init進(jìn)程就好像是一個(gè)民政局,專(zhuān)門(mén)負(fù)責(zé)處理孤兒進(jìn)程的善后工作。每當(dāng)出現(xiàn)一個(gè)孤兒進(jìn)程的時(shí)候,內(nèi)核就把孤 兒進(jìn)程的父進(jìn)程設(shè)置為init,而init進(jìn)程會(huì)循環(huán)地wait()它的已經(jīng)退出的子進(jìn)程。這樣,當(dāng)一個(gè)孤兒進(jìn)程凄涼地結(jié)束了其生命周期的時(shí)候,init進(jìn)程就會(huì)代表黨和政府出面處理它的一切善后工作。因此孤兒進(jìn)程并不會(huì)有什么危害。
我們來(lái)測(cè)試一下(創(chuàng)建完子進(jìn)程后,主進(jìn)程所在的這個(gè)腳本就退出了,當(dāng)父進(jìn)程先于子進(jìn)程結(jié)束時(shí),子進(jìn)程會(huì)被init收養(yǎng),成為孤兒進(jìn)程,而非僵尸進(jìn)程),文件內(nèi)容

import os
import sys
import time

pid = os.getpid()
ppid = os.getppid()
print 'im father', 'pid', pid, 'ppid', ppid
pid = os.fork()
#執(zhí)行pid=os.fork()則會(huì)生成一個(gè)子進(jìn)程
#返回值pid有兩種值:
#    如果返回的pid值為0,表示在子進(jìn)程當(dāng)中
#    如果返回的pid值>0,表示在父進(jìn)程當(dāng)中
if pid > 0:
    print 'father died..'
    sys.exit(0)

# 保證主線程退出完畢
time.sleep(1)
print 'im child', os.getpid(), os.getppid()

執(zhí)行文件,輸出結(jié)果:
im father pid 32515 ppid 32015
father died..
im child 32516 1

子進(jìn)程已經(jīng)被pid為1的init進(jìn)程接收了,所以僵尸進(jìn)程在這種情況下是不存在的,存在只有孤兒進(jìn)程而已,孤兒進(jìn)程聲明周期結(jié)束自然會(huì)被init來(lái)銷(xiāo)毀。

三:僵尸進(jìn)程危害場(chǎng)景:

例如有個(gè)進(jìn)程,它定期的產(chǎn) 生一個(gè)子進(jìn)程,這個(gè)子進(jìn)程需要做的事情很少,做完它該做的事情之后就退出了,因此這個(gè)子進(jìn)程的生命周期很短,但是,父進(jìn)程只管生成新的子進(jìn)程,至于子進(jìn)程 退出之后的事情,則一概不聞不問(wèn),這樣,系統(tǒng)運(yùn)行上一段時(shí)間之后,系統(tǒng)中就會(huì)存在很多的僵死進(jìn)程,倘若用ps命令查看的話,就會(huì)看到很多狀態(tài)為Z的進(jìn)程。 嚴(yán)格地來(lái)說(shuō),僵死進(jìn)程并不是問(wèn)題的根源,罪魁禍?zhǔn)资钱a(chǎn)生出大量僵死進(jìn)程的那個(gè)父進(jìn)程。因此,當(dāng)我們尋求如何消滅系統(tǒng)中大量的僵死進(jìn)程時(shí),答案就是把產(chǎn)生大 量僵死進(jìn)程的那個(gè)元兇槍斃掉(也就是通過(guò)kill發(fā)送SIGTERM或者SIGKILL信號(hào)啦)。槍斃了元兇進(jìn)程之后,它產(chǎn)生的僵死進(jìn)程就變成了孤兒進(jìn) 程,這些孤兒進(jìn)程會(huì)被init進(jìn)程接管,init進(jìn)程會(huì)wait()這些孤兒進(jìn)程,釋放它們占用的系統(tǒng)進(jìn)程表中的資源,這樣,這些已經(jīng)僵死的孤兒進(jìn)程 就能瞑目而去了。

四:測(cè)試

1、產(chǎn)生僵尸進(jìn)程的程序test.py內(nèi)容如下
#coding:utf-8
from multiprocessing import Process
import time,os

def run():
    print('子',os.getpid())

if __name__ == '__main__':
    p=Process(target=run)
    p.start()
    
    print('主',os.getpid())
    time.sleep(1000)
2、在unix或linux系統(tǒng)上執(zhí)行
[root@vm172-31-0-19 ~]# python3  test.py &
[1] 18652
[root@vm172-31-0-19 ~]# 主 18652
子 18653

[root@vm172-31-0-19 ~]# ps aux |grep Z
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     18653  0.0  0.0      0     0 pts/0    Z    20:02   0:00 [python3] <defunct> #出現(xiàn)僵尸進(jìn)程
root     18656  0.0  0.0 112648   952 pts/0    S+   20:02   0:00 grep --color=auto Z

[root@vm172-31-0-19 ~]# top #執(zhí)行top命令發(fā)現(xiàn)1zombie
top - 20:03:42 up 31 min,  3 users,  load average: 0.01, 0.06, 0.12
Tasks:  93 total,   2 running,  90 sleeping,   0 stopped,   1 zombie
%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1016884 total,    97184 free,    70848 used,   848852 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   782540 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                                                        
root      20   0   29788   1256    988 S  0.3  0.1   0:01.50 elfin                                                                                                                      
3、

等待父進(jìn)程正常結(jié)束后會(huì)調(diào)用wait/waitpid去回收僵尸進(jìn)程
但如果父進(jìn)程是一個(gè)死循環(huán),永遠(yuǎn)不會(huì)結(jié)束,那么該僵尸進(jìn)程就會(huì)一直存在,僵尸進(jìn)程過(guò)多,就是有害的
解決方法一:殺死父進(jìn)程
解決方法二:對(duì)開(kāi)啟的子進(jìn)程應(yīng)該記得使用join,join會(huì)回收僵尸進(jìn)程
參考python2源碼注釋

class Process(object):
    def join(self, timeout=None):
        '''
        Wait until child process terminates
        '''
        assert self._parent_pid == os.getpid(), 'can only join a child process'
        assert self._popen is not None, 'can only join a started process'
        res = self._popen.wait(timeout)
        if res is not None:
            _current_process._children.discard(self)

in方法中調(diào)用了wait,告訴系統(tǒng)釋放僵尸進(jìn)程。discard為從自己的children中剔除

解決方法三http://blog.csdn.net/u010571844/article/details/50419798

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我們知道在unix/linux中,子進(jìn)程的結(jié)束和父進(jìn)程的運(yùn)行是一個(gè)異步過(guò)程, 當(dāng)一個(gè)進(jìn)程完成它的工作終止之后,它的...
    丶Em1tu0F閱讀 992評(píng)論 0 3
  • 基本概念 我們知道在unix/linux中,正常情況下,子進(jìn)程是通過(guò)父進(jìn)程創(chuàng)建的,子進(jìn)程在創(chuàng)建新的進(jìn)程。子進(jìn)程的結(jié)...
    01_小小魚(yú)_01閱讀 333評(píng)論 0 0
  • 孤兒進(jìn)程與僵尸進(jìn)程[總結(jié)] 1、前言 之前在看《unix環(huán)境高級(jí)編程》第八章進(jìn)程時(shí)候,提到孤兒進(jìn)程和僵尸進(jìn)程,一直...
    徐德東閱讀 261評(píng)論 0 0
  • 今天用手機(jī)看視頻的時(shí)候,看到一個(gè)節(jié)目,叫做圓桌派。 這個(gè)節(jié)目給我的感覺(jué)就是一個(gè)辯論,拋出一個(gè)論題,然后每個(gè)人都...
    whb3246閱讀 187評(píng)論 0 0
  • 我害怕孤單,卻愛(ài)上了寂寞。
    d00c63d6777c閱讀 164評(píng)論 0 0

友情鏈接更多精彩內(nèi)容