linux mysql 僵尸进程_Linux 系统中僵尸进程
Linux 系統中僵尸進程和現實中僵尸(雖然我也沒見過)類似,雖然已經死了,但是由于沒人給它們收尸,還能四處走動。僵尸進程指的是那些雖然已經終止的進程,但仍然保留一些信息,等待其父進程為其收尸。
僵尸進程如何產生的?
如果一個進程在其終止的時候,自己就回收所有分配給它的資源,系統就不會產生所謂的僵尸進程了。那么我們說一個進程終止之后,還保留哪些信息?為什么終止之后還需要保留這些信息呢?
一個進程終止的方法很多,進程終止后有些信息對于父進程和內核還是很有用的,例如進程的 ID號、進程的退出狀態、進程運行的CPU時間等。因此進程在終止時,回收所有內核分配給它的內存、關閉它打開的所有文件等等,但是還會保留以上極少的信 息,以供父進程使用。父進程可以使用 wait/waitpid 等系統調用來為子進程收拾,做一些收尾工作。
因此,一個僵尸進程產生的過程是:父進程調用fork創建子進程后,子進程運行直至其終止,它立即從內存中移除,但進程描述符仍然保留在內存中(進程描述符占有極少的內存空間)。子進程的狀態變成EXIT_ZOMBIE,并且向父進程發送SIGCHLD?信號,父進程此時應該調用?wait()?系 統調用來獲取子進程的退出狀態以及其它的信息。在 wait 調用之后,僵尸進程就完全從內存中移除。因此一個僵尸存在于其終止到父進程調用 wait 等函數這個時間的間隙,一般很快就消失,但如果編程不合理,父進程從不調用 wait 等系統調用來收集僵尸進程,那么這些進程會一直存在內存中。
在 Linux 下,我們可以使用 ps 等命令查看系統中僵尸進程,僵尸進程的狀態標記為‘Z’:
產生一個僵尸進程
根據上面的描述,我們很容易去寫一個程序來產生僵尸進程,如下代碼:
#include
#include
int main()
{
//fork a child process
pid_t pid = fork();
if (pid > 0)?? //parent process
{
printf("in parent process, sleep for one miniute...zZ...n");
sleep(60);
printf("after sleeping, and exit!n");
}
else if (pid == 0)
{
//child process exit, and to be a zombie process
printf("in child process, and exit!n");
exit(0);
}
return 0;
}
父進程并沒有寫 wait 等系統調用函數,因此在子進程退出之后變成僵尸進程,父進程并沒有為其去收尸。我們使用下面命令編譯運行該進程,然后查看系統中進程狀態:
guohailin@guohailin:~/Documents$ gcc zombie.c -o zombie
guohailin@guohailin:~/Documents$ ./zombie
in parent process, sleep for one miniute...zZ...
in child process, and exit!
# 打開另一個終端:
guohailin@guohailin:~$ ps aux | grep -w 'Z'
1000??????2211??1.2??0.0??????0???? 0 ?????????Z????13:24?? 6:53 [chromium-browse]
1000??????4400??0.0??0.0??????0???? 0 ?????????Z????10月16?? 0:00 [fcitx]
1000???? 10871??0.0??0.0??????0???? 0 pts/4????Z+?? 22:32?? 0:00 [zombie]
從上面可以看出,系統中多了一個僵尸進程。但如果等父進程睡眠醒來退出之后,我們再次查看系統進程信息,發現剛才的僵尸進程不見了。
guohailin@guohailin:~/Documents$ ./zombie
in parent process, sleep for one miniute...zZ...
in child process, and exit!
after sleeping, and exit!
guohailin@guohailin:~/Documents$ ps aux | grep -w 'Z'
1000 ? ? ?2211 ?1.2 ?0.0 ? ? ?0 ? ? 0 ? ? ? ? ?Z ? ?13:24 ? 6:53 [chromium-browse]
1000 ? ? ?4400 ?0.0 ?0.0 ? ? ?0 ? ? 0 ? ? ? ? ?Z ? ?10月16 ? 0:00 [fcitx]
這是為什么呢?父進程到死都也沒有為其子進程收尸呀,怎么父進程退出之后,那個僵尸進程 就消失了呢?難道父進程在退出時會為子進程收拾嗎?其實不然….真正的原因是:父進程死掉之后,其所有子進程過繼給 init 進程,init 進程成為該僵尸進程的新進程,init 進程會周期性地去調用 wait 系統調用來清除它的僵尸孩子。因此,你會發現上面例子中父進程死掉之后,僵尸進程也跟著消失,其實是 init 進程為其收尸的!
怎樣避免僵尸進程的產生
不能使用 kill 后接?SIGKILL?信號這樣的命令像殺死普通進程一樣殺死僵尸進程,因為僵尸進程是已經死掉的進程,它不能再接收任何信號。事實上,如果系統中僵尸進程并不多的話,我們也無需去消除它們,少數的僵尸進程并不會對系統的性能有什么影響。
那么在編程時,如果能避免系統中大量產生僵尸進程呢?根據上面描述的,子進程在終止時會 向父進程發 SIGCHLD 信號,Linux 默認是忽略該信號的,我們可以顯示安裝該信號,在信號處理函數中調用 wait 等函數來為其收尸,這樣就能避免僵尸進程長期存在于系統中了。示例代碼如下:
#include
#include
#include
#include
#include
sig_atomic_t child_exit_status;
void clean_up_child_process(int signal_num)
{
/* clean up child process */
int status;
wait (&status);
/* store its exit status in a global variable */
child_exit_status = status;
}
int main()
{
/* handle SIGCHLD by calling clean_up_child_process??*/
struct sigaction sigchild_action;
memset(&sigchild_action, 0, sizeof(sigchild_action));
sigchild_action.sa_handler = &clean_up_child_process;
sigaction(SIGCHLD, &sigchild_action, NULL);
/* fork a child, and let the child process dies before parent */
pid_t c_pid;
c_pid = fork();
if (c_pid > 0)
{
printf("in parent process, and sleep for on mininute...zZ...n");
sleep(60);
}
else if(c_pid == 0)
{
printf("in child process, and exit nown");
exit(0);
}
else
{
printf("fork failed!n");
}
return 0;
}
總結
以上是生活随笔為你收集整理的linux mysql 僵尸进程_Linux 系统中僵尸进程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 后扣带回的三分视角
- 下一篇: ConvE:Convolutional