如何清理僵尸进程(转载)

如何清理僵尸进程(转载),第1张

首先说说:僵尸进程是什么?

僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源。

我们都知道进程的工作原理。我们启动一个程序,开始我们的任务,然后等任务结束了,我们就停止这个进程。进程停止后, 该进程就会从进程表中移除。

僵尸进程啥危害?

由于子进程的结束和父进程的运行是一个不同过程,父进程无法判断子进程什么时候结束. 或者说不知道 子进程什么时候结束,而丢失子进程结束时的状态信息呢? 不会。因为UNⅨ提供可用机制,这种机制就是:在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程释放. 但这样就导致了问题,如果进程不更新掉,那么保留的那段信息就不会释放,其进程号就会一直被占用,系统进程号有限,如果大量的产生僵尸进程,可能因为进程太多占用无法产生新的进程,这应该避免。

1、那么如何查看僵尸进程呢?

如何查看 linux 系统上的僵尸进程,或者如何统计有多少僵尸进程?

命令:ps -ef | grep defunct

或者查找状态为Z的进程,Z就是代表zombie process,僵尸进程的意思,使用top命令查看,如果状态为Z也就是(zombie process)说明它就是僵尸进程。

Tasks: 85 total, 2 running, 82 sleeping, 0 stopped, 0 zombie

top命令也可以查看。或者使用下面的命令:

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

2、如何杀死僵尸进程?

一般僵尸进程很难直接kill掉,不过您可以kill父进程(僵尸父亲),“父亲”死后,僵尸进程成为”孤儿进程”,接着给init它始终会负责清理僵尸进程.紧随着父亲消失了,儿子也就跟着消失了。

ps -e -o ppid,stat | grep Z | cut –d” ” -f2 | xargs kill -9

kill -HUP ps -A -ostat,ppid | grep -e ’^[Zz]‘ | awk ’{print $2}’

当然了,如果您精通其他语言的话,当真是简单方便

3、如何避免僵尸进程?

对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结 束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。

signal(SIGCHLD,SIG_IGN)

用两次fork()参数,而且使紧跟的子进程直接退出,让孙子进程成为孤儿进程,从而init进程将负责清除这个孤儿进程

Linux 系统中,进程就是一个程序的运行实例。它可能运行在前端(比如有交互的进程),也可能运行在后端(比如无交互或自动运行的进程)。它可能是一个父进程(运行期间创建了其他进程),也可能是一个子进程(由其他进程所创建)。

在 Linux 系统中,除 PID 为 0 的第一个 init 进程(或 systemd )外,其余进程都有父进程。进程也可以拥有自己的子进程。

你可以通过使用 pstree 命令 来查看进程的树型结构,你可以清晰的看到各个进程的“家族树”。

在 Linux 系统中,正常情况下,子进程死亡后其父进程会接收到通知进行一些例如释放内存之类的清理操作。但是,如果父进程未收到通知察觉子进程死亡,那么子进程就进入了“僵死”状态。

这就是僵死进程产生的原因。

僵尸进程并不可怕,少量的僵尸进程对系统影响并不大。但如果系统的内存已经所剩不多或者有太多的僵尸进程在耗掉内存,问题会变得糟糕。

同样,大部分 Linux 系统进程最大 PID 设置为 32768,如果过多僵尸进程导致其他重要任务没有 PID 可用,那么你的系统会发生崩溃。

特别当存在一个编码糟糕的程序开始大量产生僵尸进程的时候,这种情况经常发生。在这种情况下,我们就需要找到并杀死僵尸进程。

在linux系统中,进程有如下几种状态,它们随时可能处于以上状态中的一种:

我们可以在命令终端中通过 top命令 来查看系统进程和它的当前状态。

命令如下:

如上面截图中看到的,其中共有 250 个任务(进程),其中 1 个处在 “运行中running” 状态,248 个进程处于 “休眠sleep” 状态,还有一个处于 “僵尸zombie” 状态。

现在问题进入下一步,如何杀死 “僵尸” 进程?

僵尸进程对系统来说就是已经死亡的进程,那么如何杀掉一个已经死亡的进程呢?

方法很简单,我们只需要通过如下ps命令就可以列举僵尸进程,得到它们的进程 ID。

ps ux 命令输出的第 8 列显示了进程状态。上述命令将会打印所有处在 Z+ 状态(表示僵尸状态)的进程。

确认了进程 ID 后,我们可以得到它的父进程 ID:

你也可以将上述两个命令结合在一起,直接得到僵尸进程的 PID 及其父进程的 PID:

通过以上命令都可以找到僵尸进程,然后你就可以通过 kill命 令杀掉了。

或者通过如下命令查看僵尸进程:

该命令输出结果上你可以直接看出其父进程ID,这时候你直接使用kill命令杀掉即可。

再次运行 ps 命令或 top 命令,你可以验证僵尸进程是否已经被杀死。

通过本文你将认识 Linux 系统中的僵尸进程以及明白了其产生的主要原因。同时,你也能学会如何查找僵尸僵尸进程并杀掉僵尸进程。

当然你也可以自己别写脚本设置成定时运行任务自动来替你做这些工作。

In UNIX System terminology, a process that has terminated,but whose parent has not yet waited for it is called a zombie.

在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid), 那么它将变成一个僵尸进程.  在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用 waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程。

我们可以用top命令来查看服务器当前是否有僵尸进程,在下图中可以看到僵尸进程数的提示,如果数字大于0,那么意味着服务器当前存在有僵尸进程:

#ps -ef | grep defunct

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

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

一般僵尸进程很难直接kill掉,不过您可以kill僵尸爸爸。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。

子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。就是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,而此时,尽管对它的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。

我们用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

一条简单的命令,直接查找僵死进程,然后将父进程杀死

#  ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9

# ps -e -o ppid,stat | grep Z | cut -d” ” -f2 | xargs kill -9

# kill -HUP  $(ps -A -ostat,ppid | grep -e ’^[Zz]‘ | awk ’{print $2}’)

处理SIGCHLD信号并不是必须的,但对于某些进程,特别是服务器进程往往在请求到来时生成子进程处理请求。

如果父进程不等待子进程结束,子进程将成为僵尸进程(zombie)从而占用系统资源。如果父进程等待子进程结束,将增加父进程的负担,影响服务器进程的并发性能。

在Linux下 可以简单地将 SIGCHLD信号的操作设为SIG_IGN。

这样,内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同,BSD4下必须显式等待子进程结束才能释放僵尸进程。

或者用两次fork(),而且使紧跟的子进程直接退出,是的孙子进程成为孤儿进程,从而init进程将负责清除这个孤儿进程!


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/591795.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-07-08
下一篇2023-07-08

发表评论

登录后才能评论

评论列表(0条)

    保存