|
|
在维护服务器的时候,发现有多个nova-novncproxy的僵尸进程。' F1 H4 n: k9 u1 z2 ?9 I6 W
! ~& x) ]$ X0 }3 x! x* A# @5 N
26327 ? S 0:05 \_ /usr/bin/python /usr/bin/nova-novncproxy --config-file=/etc/nova/nova.conf& j1 Q0 @# m/ w U [- ^ ?
4765 ? Z 0:00 \_ [nova-novncproxy] <defunct>
8 p; Y! V3 E! v 4766 ? Z 0:00 \_ [nova-novncproxy] <defunct>3 `5 x+ s9 W) g3 B) {! ]
4767 ? Z 0:00 \_ [nova-novncproxy] <defunct>
* R# J7 d8 v- Z0 e 4768 ? Z 0:00 \_ [nova-novncproxy] <defunct>
( l! X& L2 o0 D! q 4769 ? Z 0:00 \_ [nova-novncproxy] <defunct>
7 j7 N6 s) x6 M# ?! N之前对于僵尸进程的了解并不深,该如何处理。$ k; b0 @/ _6 @- M& L: R- F
: U7 }+ U* o# x- y- a$ E4 X: X& C
定义
. _( s% ~' Q. l1 T$ }8 A: L+ t( o& z/ l1 L/ I: g2 ]
In UNIX System terminology, a process that has terminated,but whose parent has not yet waited for it, is called a zombie.6 I$ g- W3 p" w8 ~2 t$ M
/ {9 E' e1 J- \8 v8 O8 E5 T+ L, }
在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程. 在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用 waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程。
# J5 e4 Y: a$ l7 y& T: n
/ }/ @2 p' r3 c- V1 G$ D! |! n如何查看linux系统上的僵尸进程,如何统计有多少僵尸进程?8 U0 Z: E" U V0 D6 Q9 ?
& }4 y7 L5 [& {3 n$ [# v#ps -ef | grep defunct# ?, _3 E- Z( A1 b+ ~7 C
2 G$ S) A5 k* _# H8 h# o Y. V或者查找状态为Z的进程,Z就是代表zombie process,僵尸进程的意思。
. T) P( V. [* _9 H: h7 f& w% W, K% |5 E9 }6 R/ P
另外使用top命令查看时有一栏为S,如果状态为Z说明它就是僵尸进程。! a* J/ U; b P/ g+ j. M
; g0 [; C. Q4 | K8 g1 P3 j$ qTasks: 95 total, 1 running, 94 sleeping, 0 stopped, 0 zombie
- Y$ j( \5 w) u1 \+ ?# G/ [
$ i) \- f/ k- Ttop命令中也统计了僵尸进程。或者使用下面的命令:" ^& l+ T( I) `5 w1 K% ~9 _9 O# Q5 n$ _$ G
4 _. z* j9 S: C1 _, @7 d0 Z) Eps -ef | grep defunct | grep -v grep | wc -l
* a! c1 h/ {7 Z$ A% U P
, P# o: v1 B' R/ Z; h/ |7 }5 T如何杀死僵尸进程呢?
7 L. c! E) W/ Z. y一般僵尸进程很难直接kill掉,不过您可以kill僵尸爸爸。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。; |5 b7 T! [/ N7 D! Q: O
- u9 W8 K' l5 G: |/ mps -e -o ppid,stat | grep Z | cut -d” ” -f2 | xargs kill -9
; Y$ x% D8 V0 C9 \0 h6 d/ o5 c; a# l! y1 b7 c. N
或" Y+ a5 Y0 x; Y
5 e7 N4 ?; G- W3 |kill -HUP `ps -A -ostat,ppid | grep -e ’^[Zz]‘ | awk ’{print $2}’`
0 h q7 z+ |2 v! i I5 U, w
3 g- i* _* z% y当然您可以自己编写更好的shell脚本,欢迎与大家分享。
- |3 {+ E7 J. K7 S- H+ C' R" D# V' _; \1 S/ N& M+ U- x
我将nova-novncproxy stop后再start,僵尸进程即消失,问题解决。
% j+ o; h# w/ V% D* O5 B8 `7 c/ R" a/ ]* K4 A9 S5 c9 O3 w
另外子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。就是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,而此时,尽管对它的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。* y+ ^6 _: c: o0 ~+ l8 R5 J
$ I; H i( @. P9 o9 ^如何避免僵尸进程呢?
1 D5 R, ^$ T! J) N2 v% R处理SIGCHLD信号并不是必须的。但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。; ^( A5 R; W4 }* f
signal(SIGCHLD,SIG_IGN);
# A2 _1 V% O& Z& k- s4 n, i$ W这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程7 P; d8 o) z: u$ c
; J6 q* [7 A, ?; ^3 c或者/ x( \) P4 h: M( s$ d
0 p& F2 {5 d5 m; _! S' P, g2 h用两次fork(),而且使紧跟的子进程直接退出,是的孙子进程成为孤儿进程,从而init进程将负责清除这个孤儿进程。 |
|