當前位置:編程學習大全網 - 編程語言 - 應用程序關閉了也壹直保留在任務管理器的進程中是怎麽回事?

應用程序關閉了也壹直保留在任務管理器的進程中是怎麽回事?

所謂的僵屍進程!

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

僵屍進程是指的父進程已經退出,而該進程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):

main()

{

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

.

.

fork();

fork();

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

現在,子進程死亡時父進程沒有 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 用重手法處理它們。

  • 上一篇:軟件測試工程師面試主要有哪些問題?如何回答?
  • 下一篇:hadoop 壹個job可以應用joncontrol嗎
  • copyright 2024編程學習大全網