僵死(Zombie)進程
進程在它的生命周期有幾種狀態:睡眠,可運行,停止,正在運行和僵死狀態。所謂僵死進程,指的是一個進程已經退出,它的內存和相關的資源已經被內核釋放掉,但是在進程表中這個進程項(entry)還保留著,以便它的父進程得到它的退出狀態。一個進程退出時,它的父進程會收到一個SIGCHLD信號。一般情況下,這個信號的句柄通常執行wait系統調用,這樣處于僵死狀態的進程會被刪除。如果父進程沒有這么做,結果是什么呢?毫無疑問,進程會處于僵死狀態。實際上,僵死進程不會對系統有太大的傷害,最多就是它的進程號(PID)和進程表中的進程項系統不能使用。
ps aux|grep defunct
找出僵死進程
注意用kill命令不能殺死這種進程。原因是它已經退出了,什么也沒有了,自然無法收到任何信號。
刪除僵尸進程的根本方法是讓它的父進程調用wait來處理SIGCHLD信號。有兩種方式可以做到這一點。一種方法是改變它的父進程??梢杂胟ill命令殺死它的父進程,這樣init變成它的新的父進程,而init會定時地執行wait系統調用。另一種方式是使用調試器,在父進程中執行wait系統調用。如果知道了父進程的程序名稱和它的進程號,運行下面命令:
%gdb `parent application name` `parent pid`
(gdb) set unwindonsignal on
(gdb) call wait(pid of zombie process)
gdb會在父進程中調用wait,從而達到我們的目的。注意,unwindonsignal要被set為on, 它告訴gdb把堆?;謴偷秸{用wait之前的狀態。要不然父進程會crash。 在程序中避免僵死進程除了顯式調用wait或waitpid外,也可以使用下面的代碼來避免僵死進程(這兒假設父進程對子進程的狀態不感興趣),它遵循POSIX,是可移植的。
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_NOCLDWAIT;
sigemptyset (&sa.sa_mask);
sigaction (SIGCHLD, &sa, NULL);
參考exit(2)手冊頁。
進程在它的生命周期有幾種狀態:睡眠,可運行,停止,正在運行和僵死狀態。所謂僵死進程,指的是一個進程已經退出,它的內存和相關的資源已經被內核釋放掉,但是在進程表中這個進程項(entry)還保留著,以便它的父進程得到它的退出狀態。一個進程退出時,它的父進程會收到一個SIGCHLD信號。一般情況下,這個信號的句柄通常執行wait系統調用,這樣處于僵死狀態的進程會被刪除。如果父進程沒有這么做,結果是什么呢?毫無疑問,進程會處于僵死狀態。實際上,僵死進程不會對系統有太大的傷害,最多就是它的進程號(PID)和進程表中的進程項系統不能使用。
ps aux|grep defunct
找出僵死進程
注意用kill命令不能殺死這種進程。原因是它已經退出了,什么也沒有了,自然無法收到任何信號。
刪除僵尸進程的根本方法是讓它的父進程調用wait來處理SIGCHLD信號。有兩種方式可以做到這一點。一種方法是改變它的父進程??梢杂胟ill命令殺死它的父進程,這樣init變成它的新的父進程,而init會定時地執行wait系統調用。另一種方式是使用調試器,在父進程中執行wait系統調用。如果知道了父進程的程序名稱和它的進程號,運行下面命令:
%gdb `parent application name` `parent pid`
(gdb) set unwindonsignal on
(gdb) call wait(pid of zombie process)
gdb會在父進程中調用wait,從而達到我們的目的。注意,unwindonsignal要被set為on, 它告訴gdb把堆?;謴偷秸{用wait之前的狀態。要不然父進程會crash。 在程序中避免僵死進程除了顯式調用wait或waitpid外,也可以使用下面的代碼來避免僵死進程(這兒假設父進程對子進程的狀態不感興趣),它遵循POSIX,是可移植的。
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_NOCLDWAIT;
sigemptyset (&sa.sa_mask);
sigaction (SIGCHLD, &sa, NULL);
參考exit(2)手冊頁。