Contents

如何清理Linux僵尸进程

1. 概述

在本教程中,我们将了解僵尸进程 以及清理它们的方法。首先,我们将了解各种进程状态。然后,我们将检查识别僵尸进程的方法。最后,我们将找到解决问题的方法。

2. 什么是僵尸进程

Linux 中的僵尸进程有时也称为失效或死进程。它们是已完成执行的进程,但它们的条目并未从进程表中删除。

2.1. 进程状态

Linux 维护着所有正在运行的进程及其状态的进程表。让我们简要概述一下各种进程状态:

  1. Running (R):这些进程当前正在运行或可运行。
  2. 等待 (S/D):这些是等待事件或资源的进程。等待可以是可中断睡眠 (S) 或不可中断睡眠 (D)。
  3. 已停止 (T):我们可以通过发送适当的信号来停止Linux 进程。
  4. Zombie (Z):当一个进程完成它的任务时,它会释放它正在使用的系统资源并清理它的内存。但是,它从进程表中的条目不会被删除,它的状态设置为EXIT_ZOMBIE

在接下来的小节中,我们将更好地理解僵尸进程的概念。

2.2. 创建僵尸进程

当一个进程完成其工作时,Linux 内核通过发送SIGCHLD 信号通知退出进程的父进程。然后父进程执行wait() 系统调用以读取子进程的状态并读取其退出代码。这也从进程表中清除了子进程的条目,因此进程结束。

但是,**如果父进程未编程为在创建子进程时执行wait()系统调用,**则不会发生正确的清理。在这种情况下,父进程无法监控子进程的状态变化,最终忽略了SIGCHLD信号。这导致已完成进程的僵尸状态停留在进程表中,因此它作为僵尸进程出现在进程列表中。

另一个有趣的情况是当父进程无法处理或接收来自子进程的**SIGCHLD信号时。**这种情况也会导致僵尸的产生。

2.3. 僵尸进程的识别

我们可以使用ps 命令识别僵尸列表:

$ ps ux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
shubh        9  0.0  0.0  16916  2760 tty1     S    Dec19   0:00 /bin/bash --login
shubh      108  0.0  0.0      0     0 tty1     Z    16:25   0:00 [zombie] <defunct> 
shubh      109  0.0  0.0  17384  1928 tty2     R    16:25   0:00 ps ux

从输出中可以看出,STAT列中的Zps命令输出中的zombiedefunct模式可用于识别僵尸。

让我们使用awk 命令根据Z进程状态进一步过滤输出:

$ ps ux | awk '{if($8=="Z") print}'
shubh       108  0.0  0.0      0     0 tty1     Z    16:25   0:00 [zombie] <defunct>

另一种检查僵尸进程数量和列表的便捷方法是使用top 命令:

$ top
Tasks:   8 total,   1 running,   6 sleeping,   0 stopped,   1 zombie
%Cpu(s):  0.7 us,  1.6 sy,  0.0 ni, 96.5 id,  0.0 wa,  1.2 hi,  0.0 si,  0.0 st
KiB Mem :  8269412 total,  3161228 free,  4878832 used,   229352 buff/cache
KiB Swap: 15483260 total, 14830144 free,   653116 used.  3256848 avail Mem
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0    8936    192    148 S   0.0  0.0   0:00.17 init
    8 root      20   0    8936     96     56 S   0.0  0.0   0:00.00 init
    9 shubh     20   0   16916   2748   2640 S   0.0  0.0   0:00.43 bash
   76 root      20   0    8936    224    184 S   0.0  0.0   0:00.00 init
   77 shubh     20   0   16784   3432   3332 S   0.0  0.0   0:00.35 bash
  161 shubh     20   0       0      0      0 Z   0.0  0.0   0:00.00 zombie
  162 shubh     20   0   17624   2084   1508 R   0.0  0.0   0:00.00 top

在这里,连同其他详细信息,我们还可以在输出顶部的摘要中看到僵尸进程的数量。

3. 清理僵尸进程

我们不能真正杀死僵尸进程,因为它已经死了。但是,我们可以使用一些解决方法来清理僵尸进程。

3.1. 使用SIGCHLD信号

我们可以手动向僵尸进程的父进程发送SIGCHLD信号。因此,它将提示父进程触发wait()系统调用,这将从进程表中清除已失效的子进程

让我们找到已失效进程的父 ID:

$ ps -A -ostat,pid,ppid | grep -e '[zZ]'
Z      108   103

这列出了僵尸进程的STAT列、进程 ID 和父进程 ID。接下来,让我们使用kill 命令向父进程发送SIGCHLD信号

kill -s SIGCHLD 103

但是,并不能真正保证向父进程发送SIGCHLD信号会杀死僵尸进程。它仅适用于父进程可以处理SIGCHLD信号的情况。

3.2. 杀死父进程

如果上一节讨论的方法无法清除defunct进程,我们应该考虑杀死它的父进程:

kill -9 103

这里,103是我们的已失效进程的父 ID, PID为 108

但是,杀死父进程会影响其所有子进程。因此,我们应该格外小心,并且必须在杀死父进程之前确定影响。

如果存在大量僵尸进程,或者僵尸进程的父进程是init 进程(pid =1),我们还可以考虑重新启动系统以摆脱已失效的进程。