Linux / 僵尸进程、孤儿进程 产生原因、有什么危害、如何预防(解决方案)
一、產(chǎn)生原因
1、僵尸進(jìn)程
子進(jìn)程退出,父進(jìn)程運(yùn)行,父進(jìn)程沒(méi)有調(diào)用 wait 或者 waitpid 函數(shù),那么子進(jìn)程就處于僵尸狀態(tài)(Z)。
2、孤兒進(jìn)程
子進(jìn)程運(yùn)行,父進(jìn)程退出,孤兒進(jìn)程由?init 進(jìn)程收養(yǎng),此時(shí)子進(jìn)程就變成了孤兒進(jìn)程。
3、系統(tǒng)為什么需要僵尸進(jìn)程這種進(jìn)程狀態(tài)
由于父進(jìn)程創(chuàng)建子進(jìn)程是異步的,雙方不知道各自的運(yùn)行狀態(tài),而父進(jìn)程有的時(shí)候需要知道子進(jìn)程退出時(shí)的一些信息,所以 linux 提供了一種機(jī)制,通過(guò)讓子進(jìn)程退出時(shí)向父進(jìn)程發(fā)送 SIGCHRD 信號(hào)來(lái)告知父進(jìn)程,子進(jìn)程已經(jīng)退出了。同時(shí),父進(jìn)程通過(guò)調(diào)用 wait 和 waitpid 來(lái)獲取子進(jìn)程的退出信息。
二、有什么危害
1、僵尸進(jìn)程
有很大危害。因?yàn)榻┦M(jìn)程已經(jīng)挺尸了,對(duì)系統(tǒng)沒(méi)有什么作用,但是依然在進(jìn)程表占了位置,如果 os 有大量的僵尸進(jìn)程,那么進(jìn)程號(hào)就會(huì)被大量無(wú)故占用,嚴(yán)重的話再次 fork 進(jìn)程可能失敗。
2、孤兒進(jìn)程
沒(méi)什么危害。因?yàn)樵撨M(jìn)程只是父進(jìn)程換成了 init ,依然可以正常運(yùn)行。
三、如何預(yù)防(解決方案)
1、kill 父進(jìn)程
kill 父進(jìn)程之后,僵尸進(jìn)程會(huì)變成孤兒僵尸進(jìn)程,由?init 收養(yǎng),通過(guò) init 是循環(huán) wait ,從而讓子進(jìn)程徹底退出。
2、注冊(cè) SIGCHRD 信號(hào)的信號(hào)處理函數(shù),在函數(shù)中調(diào)用 wait(調(diào)用者堵塞) 或者 waitpid(可以配置調(diào)用者不堵塞) 。
3、fork 兩次,創(chuàng)建子進(jìn)程,子進(jìn)程在創(chuàng)建孫進(jìn)程,最后 kill 子進(jìn)程,那么孫進(jìn)程就由 init 收養(yǎng)。
栗子:
#include <iostream> #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/types.h>void signalproc(int isig) {int istatus;waitpid(SIG_BLOCK, &istatus, WNOHANG); }int main() {signal(SIGCHLD, signalproc);pid_t pid;int r = fork();if (r < 0)std::cout << "創(chuàng)建進(jìn)程失敗!" << std::endl;else if (r == 0){std::cout << "子進(jìn)程開(kāi)始運(yùn)行!" << std::endl;int r1 = fork();if (r < 0)std::cout << "創(chuàng)建孫進(jìn)程失敗!" << std::endl;else if (r1 == 0){std::cout << "孫進(jìn)程開(kāi)始運(yùn)行,并進(jìn)入循環(huán)!" << std::endl;while (true){std::cout << "Sun" << std::endl;sleep(1);}}std::cout << "子進(jìn)程退出" << std::endl;exit(0);}std::cout << "父進(jìn)程開(kāi)始進(jìn)入循環(huán)!" << std::endl;while (true){std::cout << "parent" << std::endl;sleep(1);}return 0; }結(jié)果:
父進(jìn)程開(kāi)始進(jìn)入循環(huán)! parent 子進(jìn)程開(kāi)始運(yùn)行! 子進(jìn)程退出 孫進(jìn)程開(kāi)始運(yùn)行,并進(jìn)入循環(huán)! Sun parent Sun parent Sun parent Sun parent輸入指令:
ps -eo pid,ppid,sid,comm,stat | grep -E 'bash|fork'?結(jié)果:
13997 2539 13997 bash Ss 15816 2539 15816 bash Ss 15939 15816 15816 forktest S+ 15941 1210 15816 forktest S+注意:
由于我的系統(tǒng)是 ubuntu 18.04,所以 forktest 的孫進(jìn)程的父進(jìn)程是 1210,不是 init 。1210 進(jìn)程是 systemd 進(jìn)程,該進(jìn)程的具體含義后續(xù)有時(shí)間會(huì)說(shuō)明
?
?
(SAW:Game Over!)
總結(jié)
以上是生活随笔為你收集整理的Linux / 僵尸进程、孤儿进程 产生原因、有什么危害、如何预防(解决方案)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux / offsetof 和 c
- 下一篇: Linux / 守护进程