[实践Ok]相当详细描述了Linux下查看及杀僵尸进程/孤儿进程/守护进程办法, 如何查看并杀死僵尸进程?

jackxiang 2010-5-25 13:37 | |
查看进程状态: ps 命令的STAT字段, top命令的S字段:Z    12849 12851 [grep] <defunct>
ps  -A -o 'stat,ppid,pid,cmd' | grep -e '^[Zz]'      #以stat字断Z打头 ,只是-o 必须加参数 -A,否则也是出不来的。
#ps  -A -o 'stat,ppid,pid,cmd' | grep -e '^[Zz]'
Zs   21717 14425 [sshd] <defunct>

一般这样用:
ps  -eo 'stat,ppid,pid,cmd' |grep -e '^[Zz]'
#ps  -eo 'stat,ppid,pid,cmd' |grep -e '^[Zz]'
Z     2985  3035 [sshd] <defunct>
Z     7032  7073 [sshd] <defunct>
Z    13322 13358 [sshd] <defunct>
Z    15954 15986 [sshd] <defunct>

自己的习惯性实践:


一)僵尸进程:
一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。

(子进程在父进程还没有来得及繁忙或Sleep等或子进程执行太快就退出,而父亲没来得及调用产生的)
产生和查看僵死进程:
ps -A -ostat,ppid,pid,cmd |grep -e '^[Zz]'|awk '{print $2}'|xargs kill -9



C语言版本,#cat defunct.c :


#./a.out &
[1] 15649

# ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'
Z    15649 15652 [a.out] <defunct>

僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程.(zombie)进程
怎样产生僵尸进程的:

     一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用 exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是 为什么系统中有时会有很多的僵尸进程。

来自:https://www.easyswoole.com/Cn/NoobCourse/PHP/Multiprocess/zombieProcess.html

二)孤儿进程:
孤儿进程指的是在其父进程执行完成或被终止后仍继续运行的一类进程。这些孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
孤儿进程没有任何危害,只是需要注意自己的代码逻辑即可. 例如:

孤儿进程和僵尸进程
僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害 。
来自:https://www.easyswoole.com/Cn/NoobCourse/PHP/Multiprocess/orphanProcess.html



三)守护进程 :
守护进程
守护进程(daemon)是一类在后台运行的特殊进程,用于执行特定的系统任务。很多守护进程在系统引导的时候启动,并且一直运行直到系统关闭。另一些只在需要的时候才启动,完成任务后就自动结束。

用户使守护进程独立于所有终端是因为,在守护进程从一个终端启动的情况下,这同一个终端可能被其他的用户使用。例如,用户从一个终端启动守护进程后退出,然后另外一个人也登录到这个终端。用户不希望后者在使用该终端的过程中,接收到守护进程的任何错误信息。同样,由终端键入的任何信号(例如中断信号)也不应该影响先前在该终端启动的任何守护进程的运行。虽然让服务器后台运行很容易(只要shell命令行以&结尾即可),但用户还应该做些工作,让程序本身能够自动进入后台,且不依赖于任何终端。

创建步骤
调用fork(),创建新进程,它会是将来的守护进程.
在父进程中调用exit,保证子进程不是父进程,成为孤儿进程
调用setsid()创建新的会话区,让进程摆脱原会话的控制、让进程摆脱原进程组的控制和让进程摆脱原控制终端的控制。(如果不进行这步,孤儿进程将会在控制终端退出后退出)
将当前目录改成根目录(如果把当前目录作为守护进程的目录,当前目录不能被卸载他作为守护进程的工作目录)
将标准输入,标注输出,标准错误重定向到/dev/null.(否则会在控制终端中输出)
重设文件创建掩码,文件创建掩码是指屏蔽掉文件创建时的对应位。由于使用fork函数新建的子进程继承了父进程的文件创建掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件创建掩码设置为0,可以大大增强该守护进程的灵活性。设置文件创建掩码的函数是umask,通常的使用方法为umask(0)。
关闭文件描述符,用fork新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系统资源,可能导致所在的文件系统无法卸载。
特点
首先,守护进程最重要的特性是后台运行。其次,守护进程必须与其运行前的环境隔离开来。这些环境包括未关闭的文件描述符、控制终端、会话和进程组、工作目录以及文件创建掩码等。这些环境通常是守护进程从执行它的父进程(特别是shell)继承下来的。最后,守护进程的启动方式有其特殊之处。它可以在Linux系统启动时从启动脚本/etc/rc.d中启动,也可以由作业控制进程crond启动,还可以由用户终端(通常是shell)执行。

除这些以外,守护进程与普通进程基本上没有什么区别。因此,编写守护进样实际上是把一个普通进程按照上述的守护进程的特性改造成为守护进程。

分类
按照服务类型分为如下几个。

系统守护进程:syslogd、login、crond、at等。
网络守护进程:sendmail、httpd、xinetd、等。
独立启动的守护进程:httpd、named、xinetd等。
被动守护进程(由xinetd启动):telnet、finger、ktalk等。

来自:https://www.easyswoole.com/Cn/NoobCourse/PHP/Multiprocess/deamon.html


=====================================================================
普通进程,父进程不主动去回收子进程的资源。
一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。产生僵尸进程的原因:
1、子进程结束后向父进程发出SIGCHLD信号,父进程默认忽略了它;
2、父进程没有调用wait()或waitpid()函数来等待子进程的结束;
处理办法:把父进程杀掉,僵尸进程会变成孤儿进程,然后过继给1号进程,而1号进程会扫描名下子进程,把 Z 状态进程回收;
这时候僵尸进程已经退出了,只保留了task_struct结构体,所以发信号(-9等信号)去处理僵尸进程是无效的;

4.僵尸进程解决办法:
  4.1 改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行 waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管对的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
  4.2 把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。
      kill -9 `ps -ef | grep "Process Name" | awk '{ print $3 }'`
      其中,“Process Name”为处于zombie状态的进程名。
  4.3 杀父进程不行的话,就尝试用skill -t TTY关闭相应终端,TTY是进程相应的tty号(终端号)。但是,ps可能会查不到特定进程的tty号,这时就需要自己判断了。
  4.4 实在不行,重启系统吧,这也是最常用到方法之一。
来自:https://blog.csdn.net/YuZhiHui_No1/article/details/53011390

查找并杀死僵尸进程:ps aux|grep Z

杀死:用SIGKILL信号杀死进程,但是僵尸进程已经死了,需要输入的命令应该是:kill -s SIGCHLD pid ,这里的pid替换成父进程的id,这样父进程就会删除所有以及完成并死掉的子进程了。




首先,我们可以用top命令来查看服务器当前是否有僵尸进程,可以看到第二行行尾有个 0 zombie,如果数字大于0,那么意味着服务器当前存在有僵尸进程
可以用ps和grep命令寻找僵尸进程
ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
命令选项说明:
-A 参数列出所有进程
-o 自定义输出字段 我们设定显示字段为 stat(状态), ppid(进程父id), pid(进程id),cmd(命令)这四个参数
因为状态为 z或者Z的进程为僵尸进程,所以我们使用grep抓取stat状态为zZ进程
运行结果参考如下
Z 12334 12339 /path/cmd
这时,我们可以使用 kill -HUP 12339来杀掉这个僵尸进程
运行后,可以再次运行ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'来确认是否将僵尸进程杀死
如果kill 子进程的无效,可以尝试kill 其父进程来解决问题,例如上面例子父进程pid是 12334,那么我们就运行
kill -HUP 12334来解决问题
但是很多僵尸进程都很难kill掉.得找到原头再去处理.

摘自:http://blog.sina.com.cn/s/blog_9426b1bd0101cu0l.html

——————————————————————————————————————————————————————

1) 检查当前僵尸进程信息

  # ps -ef | grep defunct | grep -v grep | wc -l

  175

  # top | head -2

  top - 15:05:54 up 97 days, 23:49,  4 users,  load average: 0.66, 0.45, 0.39

  Tasks: 829 total,   1 running, 479 sleeping, 174 stopped, 175 zombie

  # ps -ef | grep defunct | grep -v grep

  2) 获得杀僵尸进程语句

  # ps -ef | grep defunct | grep -v grep | awk '{print "kill -9 " $2,$3}'

  执行上面获得的语句即可, 使用信号量9, 僵尸进程数会大大减少.

  3) 过一会儿检查当前僵尸进程信息

  # ps -ef | grep defunct | grep -v grep | wc -l

  125

  # top | head -2

  top - 15:29:26 up 98 days, 12 min,  7 users,  load average: 0.27, 0.54, 0.56

  Tasks: 632 total,   1 running, 381 sleeping, 125 stopped, 125 zombie

  发现僵尸进程数减少了一些, 但还有不少啊.

  4) 再次获得杀僵尸进程语句

  # ps -ef | grep defunct | grep -v grep | awk '{print "kill -18 " $3}'

  执行上面获得的语句即可, 这次使用信号量18杀其父进程, 僵尸进程应该会全部消失.

  5) 过一会儿再检查当前僵尸进程信息

  # ps -ef | grep defunct | grep -v grep | wc -l

  0

  # top | head -2

  top - 15:39:46 up 98 days, 23 min,  7 users,  load average: 5.46, 2.20, 1.12

  Tasks: 134 total,   1 running, 133 sleeping,   0 stopped,   0 zombie

  6) 清除ZOMBIE(僵尸)进程原理

  # kill -18 PPID

  PPID是其父进程, 这个信号是告诉父进程, 该子进程已经死亡了, 请收回分配给他的资源. 如果还不行则看先看其父进程又无其他子进程, 如果有, 可能需要先kill其他子进程, 也就是兄弟进程.

  方法是:

  # kill -15 PID1 PID2

  PID1,PID2是僵尸进程的父进程的其它子进程.

  然后再kill父进程:

  # kill -15 PPID

  --End--

来源:http://blog.chinaunix.net/u3/114157/showart_2229852.html

作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:https://jackxiang.com/post/3099/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!


最后编辑: jackxiang 编辑于2020-4-18 11:14
评论列表
发表评论

昵称

网址

电邮

打开HTML 打开UBB 打开表情 隐藏 记住我 [登入] [注册]