Linux核心源碼學習之殭屍進程,linux核心源碼殭屍
孤兒進程和殭屍進程
正常的子進程fork其父進程後,二者建立父子關係。
當子進程終結時,它會通知父進程,並清空自己所佔據的記憶體,並在kernel裡留下自己的退出資訊(exit code,如果順利運行,為0;如果有錯誤或異常狀況,為>0的整數)。在這個資訊裡,會解釋該進程為什麼退出。父進程在得知子進程終結時,有責任對該子進程使用wait系統調用。這個wait函數能從kernel中取出子進程的退出資訊,並清空該資訊在kernel中所佔據的空間。這是正常的一般情況。
如果父進程早於子進程終結,子進程就會成為一個孤兒(orphand)進程。孤兒進程會被過繼給init進程,init進程也就成了該進程的父進程。init進程負責該子進程終結時調用wait函數。
當然,一個糟糕的程式也完全可能造成子進程的退出資訊滯留在kernel中的狀況(父進程不對子進程調用wait函數),這樣的情況下,子進程成為殭屍(zombie)進程。當大量殭屍進程積累時,記憶體空間會被擠占。
殭屍狀態存在的意義是什嗎?
殭屍狀態是系統中進程的一個必然狀態,也就是自身退出後向其父進程發送訊息等待回收的這一段時間,只是正常的情況下父進程能夠在很短的時間內給予處理,而殭屍進程的殭屍狀態將會持續很長的時間。
給進程設定殭屍狀態的目的是維護子進程的資訊,以便父進程在以後某個時間擷取。這些資訊包括子進程的進程ID、終止狀態以及資源利用資訊(CPU時間,記憶體使用量量等等)。
殭屍進程產生,留在記憶體中的是什嗎?
留在記憶體中的是進程的進程描述符,也就是用來描述進程的資料結構,也就是進程的task_struct執行個體。
為什麼父進程死掉之後,父進程的子殭屍進程也沒了?
如果一個進程終止,而該進程有子進程處於殭屍狀態,那麼它的所有殭屍子進程的父進程ID將被重設為1(init進程)。繼承這些子進程的init進程將清理它們(init進程將wait它們,從而去除殭屍狀態)。因為殭屍進程在父進程死掉之後成為孤兒進程,int進程負責對這些孤兒進程進行收屍的操作,應該是每隔一段時間執行一次。這也是一種出現殭屍進程的補救措施。
如何防止殭屍進程的產生?
1)想辦法wait子進程
1.在fork之後的父進程中wait子進程
2.想辦法捕獲核心在子進程結束後發送的訊息,並且在處理訊息的函數中來wait
void sig_chld( int signo ) {
pid_t pid;
int stat;
pid = wait(&stat);
printf("child %d exit\n", pid );
return;
}
int main() {
signal(SIGCHLD, &sig_chld);
}
上述過程先在main函數中給SIGCHLD訊號註冊一個訊號處理函數(sig_chld),然後在子進程退出的時候,核心遞交一個SIGCHLD的時候就會被主進程捕獲而進入訊號處理函數sig_chld,然後再在sig_chld中調用wait,就可以清理退出的子進程。這樣退出的子進程就不會成為殭屍進程。
下面的這個部落格中提到這種wait的方法存在缺陷,正確的方法應該是調用waitpid,這兩者之間有什麼區別?不知道。http://www.cnblogs.com/yuxingfirst/p/3165407.html
2)調用fork兩次。以下程式 實現了這一點。
其思想很簡單,首先fork原進程得到兒子進程,然後fork兒子進程的子進程,緊接著讓兒子進程死掉,這樣,因為兒子進程先退出,孫子進程就被init接管了,實際上與最初的父進程脫離了關係,就不會僵死了(此時孫子進程的父進程相當於是init進程)http://yejun8500.blog.163.com/blog/static/463360020104555814706/
學習Linux核心原始碼需要一些什基礎?
c語言+作業系統知識(必要條件)
Linux的殭屍進程是怎出現的
當然會成為殭屍進程,你的C、D子進程比父進程先結束,
在fork ()/execve()過程中,假設子進程結束時父進程仍存在,而父進程fork()之前既沒安裝SIGCHLD訊號處理函數調用waitpid()等待子進程結束,又沒有顯式忽略該訊號,則子進程成為殭屍進程,無法正常結束,此時即使是root身份kill -9也不能殺死殭屍進程。補救辦法是殺死殭屍進程的父進程(殭屍進程的父進程必然存在),殭屍進程成為"孤兒進程",過繼給1號進程init,init始終會負責清理殭屍進程。
殭屍進程的避免:
(1) 父進程通過wait和waitpid等函數等待子進程結束,這會導致父進程掛起。
(2) 如果父進程很忙,那麼可以用signal函數為SIGCHLD安裝handler,因為子進程結束後, 父進程會收到該訊號,可以在handler中調用wait回收。
(3) 如果父進程不關心子進程什麼時候結束,那麼可以用signal(SIGCHLD, SIG_IGN) 通知核心,自己對子進程的結束不感興趣,那麼子進程結束後,
核心會回收, 並不再給父進程發送訊號。
(4) 還有一些技巧,就是fork兩次,父進程fork一個子進程,然後繼續工作,子進程fork一 個孫進程後退出,那麼孫進程被init接管,孫進程結束後,
init會回收。不過子進程的回收 還要自己做。