1. 程式人生 > >fork兩次如何避免殭屍程序收藏

fork兩次如何避免殭屍程序收藏

  殭屍程序是指的父程序已經退出,而該程序dead之後沒有程序接受,就成為殭屍程序.(zombie)程序
  怎樣產生殭屍程序的:
  一個程序在呼叫exit命令結束自己的生命的時候,其實它並沒有真正的被銷燬,而是留下一個稱為殭屍程序(Zombie)的資料結構(系統呼叫exit,它的作用是使程序退出,但也僅僅限於將一個正常的程序變成一個殭屍程序,並不能將其完全銷燬)。在Linux程序的狀態中,殭屍程序
  是非常特殊的一種,它已經放棄了幾乎所有記憶體空間,沒有任何可執行程式碼,也不能被排程,僅僅在程序列表中保留一個位置,記載該程序的退
  出狀態等資訊供其他程序收集,除此之外,殭屍程序不再佔有任何記憶體空間。它需要它的父程序來為它收屍,如果他的父程序沒安裝SIGCHLD信
  號處理函式呼叫wait或waitpid()等待子程序結束,又沒有顯式忽略該訊號,那麼它就一直保持殭屍狀態,如果這時父程序結束了,那麼init程序自動
  會接手這個子程序,為它收屍,它還是能被清除的。但是如果如果父程序是一個迴圈,不會結束,那麼子程序就會一直保持殭屍狀態,這就是為什麼系統中有時會有很多的殭屍程序。
  怎麼檢視殭屍程序:
  利用命令ps,可以看到有標記為Z的程序就是殭屍程序。
  怎樣來清除殭屍程序:
  1.改寫父程序,在子程序死後要為它收屍。具體做法是接管SIGCHLD訊號。子程序死後,會發送SIGCHLD訊號給父程序,父程序收到此訊號後,執行waitpid()函式為子程序收屍。這是基於這樣的原理:就算父程序沒有呼叫wait,核心也會向它傳送SIGCHLD訊息,儘管對的預設處理是忽略,如果想響應這個訊息,可以設定一個處理函式。
  2.把父程序殺掉。父程序死後,殭屍程序成為"孤兒程序",過繼給1號程序init,init始終會負責清理殭屍程序.它產生的所有殭屍程序也跟著消失。
  ===========================================
  在Linux中可以用
  ps auwx
  發現殭屍程序
  a all w/ tty, including other users 所有視窗和終端,包括其他使用者的程序
  u user-oriented 面向使用者(使用者友好)
  -w,w wide output 寬格式輸出
  x processes w/o controlling ttys
  在殭屍程序後面 會標註
  ps axf
  看程序樹,以樹形方式現實程序列表
  ps axm
  會把執行緒列出來,在linux下程序和執行緒是統一的,是輕量級程序的兩種方式。
  ps axu
  顯示程序的詳細狀態
  ===========================================
  killall
  kill -15
  kill -9
  一般都不能殺掉 defunct程序
  用了kill -15,kill -9以後 之後反而會多出更多的殭屍程序
  kill -kill pid
  fuser -k pid
  可以考慮殺死他的parent process,
  kill -9 他的parent process
  ===========================================
  一個已經終止,但是其父程序尚未對其進行善後處理(獲取終止子程序的有關資訊、釋放它仍佔用的資源)的程序被稱為僵死程序(Zombie Process)。
  避免zombie的方法:
  1)在SVR4中,如果呼叫signal或sigset將SIGCHLD的配置設定為忽略,則不會產生僵死子程序。另外,使用SVR4版的sigaction,則可設定SA_NOCLDWAIT標誌以避免子程序僵死。
  Linux中也可使用這個,在一個程式的開始呼叫這個函式
  signal(SIGCHLD,SIG_IGN);
  2)呼叫fork兩次。程式8 - 5 實現了這一點。
  3)用waitpid等待子程序返回.
  ===========================================
  zombie程序是僵死程序。防止它的辦法,一是用wait,waitpid之類的函式獲得
  程序的終止狀態,以釋放資源。另一個是fork兩次
  ===========================================
  defunct程序只是在process table裡還有一個記錄,其他的資源沒有佔用,除非你的系統的process個數的限制已經快超過了,zombie程序不會有更多的壞處。
  可能唯一的方法就是reboot系統可以消除zombie程序。
  ===========================================
  任何程式都有殭屍狀態,它佔用一點記憶體資源(也就是程序表裡還有一個記錄),僅僅是表象而已不必害怕。如果程式有問題有機會遇見,解決大批量殭屍簡單有效的辦法是重起。kill是無任何效果的
  fork與zombie/defunct"
  在Unix下的一些程序的運作方式。當一個程序死亡時,它並不是完全的消失了。程序終止,它不再執行,但是還有一些殘留的小東西等待父程序收回。這些殘留的東西包括子程序的返回值和其他的一些東西。當父程序 fork() 一個子程序後,它必須用 wait() 或者 waitpid() 等待子程序退出。正是這個 wait() 動作來讓子程序的殘留物消失。
  自然的,在上述規則之外有個例外:父程序可以忽略 SIGCLD 軟中斷而不必要 wait()。可以這樣做到(在支援它的系統上,比如Linux):
  
    現在,子程序死亡時父程序沒有 wait(),通常用 ps 可以看到它被顯示為“”。它將永遠保持這樣 直到 父程序 wait(),或者按以下方法處理。
  這裡是你必須知道的另一個規則:當父程序在它wait()子程序之前死亡了(假定它沒有忽略 SIGCLD),子程序將把 init(pid 1)程序作為它的父程序。如果子程序工作得很好並能夠控制,這並不是問題。但如果子程序已經是 defunct,我們就有了一點小麻煩。看,原先的父程序不可能再 wait(),因為它已經消亡了。這樣,init 怎麼知道 wait() 這些 zombie 程序。
  答案:不可預料的。在一些系統上,init週期性的破壞掉它所有的defunct程序。在另外一些系統中,它乾脆拒絕成為任何defunct程序的父程序,而是馬上毀滅它們。如果你使用上述系統的一種,可以寫一個簡單的迴圈,用屬於init的defunct程序填滿程序表。這大概不會令你的系統管理員很高興吧?
  你的任務:確定你的父程序不要忽略 SIGCLD,也不要 wait() 它 fork() 的所有程序。不過,你也未必 要 總是這樣做(比如,你要起一個 daemon 或是別的什麼東西),但是你必須小心程式設計,如果你是一個 fork() 的新手。另外,也不要在心理上有任何束縛。
  總結:
  子程序成為 defunct 直到父程序 wait(),除非父程序忽略了 SIGCLD 。
  更進一步,父程序沒有 wait() 就消亡(仍假設父程序沒有忽略 SIGCLD )的子程序(活動的或者 defunct)成為 init 的子程序,init 用重手法處理它們。