如何在 Linux 上杀死僵尸进程

已发表: 2022-01-29
Linux 笔记本电脑上的终端窗口。
Fatmawati Achmad Zaenuri/Shutterstock

编写不佳或性能不佳的程序可能会使僵尸进程潜伏在您的 Linux 计算机中。 了解僵尸是如何产生的,以及如何最终让它们安息。

进程状态如何在 Linux 上工作

当然,Linux 必须跟踪计算机上运行的所有应用程序和守护程序。 它执行此操作的方法之一是维护进程表。 这是内核内存中的结构列表。 每个进程在此列表中都有一个条目,其中包含有关它的一些信息。

每个进程表结构都没有很多。 它们包含进程 ID、一些其他数据项和指向该进程的进程控制块 (PCB) 的指针。

PCB 包含 Linux 需要为每个进程查找或设置的许多细节。 PCB 也会随着进程的创建、处理时间和最终销毁而更新。

Linux PCB 包含超过 95 个字段。 它被定义为一个名为task_struct.h的结构,它有 700 多行。 PCB 包含以下类型的信息:

  • 进程状态:状态如下所述。
  • 进程号:它在操作系统中的唯一标识符。
  • 程序计数器:当该进程下一次获得对 CPU 的访问权时,系统将使用该地址查找应执行的进程的下一条指令。
  • Registers :此进程使用的 CPU 寄存器列表。 该列表可能包含累加器、索引寄存器和堆栈指针。
  • 打开文件列表:与此进程关联的文件。
  • CPU 调度信息:用于确定分配给此进程的 CPU 处理时间的频率和持续时间。 进程的优先级、调度队列的指针和其他调度参数都必须记录在 PCB 中。
  • 内存管理信息:有关此进程正在使用的内存的详细信息,例如进程内存的开始和结束地址,以及指向内存页面的指针。
  • I/O 状态信息:进程使用的任何输入或输出设备。

“进程状态”可以是以下任何一种:

  • R:正在运行或可运行的进程。 运行意味着它正在接收 CPU 周期并执行。 可运行进程已准备好运行并等待 CPU 插槽。
  • S:一个睡眠过程。 进程正在等待操作完成,例如输入或输出操作,或等待资源可用。
  • D:进程处于不间断睡眠状态。 它正在使用阻塞系统调用,并且在系统调用完成之前无法继续。 与“睡眠”状态不同,处于此状态的进程不会响应信号,直到系统调用完成并且执行返回到该进程。
  • T:进程已终止(停止),因为它收到了SIGSTOP信号。 它只会响应SIGKILLSIGCONT信号,它们分别杀死进程或指示它继续。 当您从前台 ( fg ) 切换到后台 ( bg)任务时,就会发生这种情况。
  • Z:僵尸进程。 当一个过程完成时,它不会消失。 它释放它正在使用的所有内存并将自己从内存中删除,但它在进程表和 PCB 中的条目仍然存在。 它的状态设置为EXIT_ZOMBIE ,并且它的父进程被通知(通过SIGCHLD信号)子进程已经完成。

广告

在 Zombie 状态下,父进程在创建子进程时调用wait()系列函数之一。 然后它等待子进程中的状态更改。 子进程是否被信号停止、继续或终止? 它是否通过运行其代码的自然完成而终止?

如果状态变化意味着子进程已停止运行,则读取其退出代码。 然后,孩子的 PCB 被销毁,它在进程表中的条目被删除。 理想情况下,这一切都发生在眨眼之间,僵尸状态的进程不会存在很长时间。

相关:如何在 Linux 上运行和控制后台进程

是什么导致 Linux 上的僵尸进程?

创建子进程时,编写不佳的父进程可能不会调用wait()函数。 这意味着没有任何东西在监视子进程中的状态变化,并且SIGCHLD信号将被忽略。 或者,也许另一个应用程序正在影响父进程的执行,这可能是由于糟糕的编程或恶意意图。

但是,如果父进程没有在子进程中监视状态变化,则不会发生适当的系统内务处理。 当子进程终止时,PCB 和进程表中的条目不会被删除。 这导致僵尸状态永远不会从 PCB 中移除。

僵尸确实会使用一些内存,但它们通常不会造成问题。 进程表中的条目很小,但是在它被释放之前,进程 ID 不能被重用。 在 64 位操作系统上,这不太可能导致任何问题,因为 PCB 比进程表条目大得多。

可以想象,大量的僵尸可能会影响其他进程可用的内存量。 但是,如果您有这么多僵尸,那么您的父应用程序或操作系统错误就会出现严重问题。

如何删除僵尸进程

你不能杀死一个僵尸进程,因为它已经死了。 它不会响应任何信号,因为它已从内存中删除——没有地方可以发送SIGKILL信号。 您可以尝试向父进程发送SIGCHLD信号,但如果在子进程终止时它不起作用,那么现在也不太可能起作用。

广告

唯一可靠的解决方案是杀死父进程。 当它终止时,它的子进程被init进程继承,它是 Linux 系统中运行的第一个进程(它的进程 ID 为 1)。

init进程定期执行必要的僵尸清理,因此要杀死它们,您只需杀死创建它们的进程即可。 top命令是查看是否有任何僵尸的便捷方法。

键入以下内容:

 最佳

这个系统有八个僵尸进程。 我们可以使用ps命令列出这些并将其输入egrep 。 同样,僵尸进程的状态标志为“Z”,您通常还会看到“已失效”。

键入以下内容:

 ps辅助| egrep "Z|已失效" 

列出了僵尸进程。

这是发现僵尸进程 ID 的一种比在top中来回滚动更简洁的方法。 我们还看到一个名为“badprg”的应用程序催生了这些僵尸。

第一个僵尸进程的进程ID是7641,但是我们需要找到它的父进程的进程ID。 我们可以通过再次使用ps来做到这一点。 我们将使用输出选项 ( -o ) 告诉ps仅显示父进程 ID,然后使用ppid=标志传递它。

广告

我们要查找的进程将通过使用-p (进程)选项来指示,然后传入僵尸进程 ID。

因此,我们键入以下命令来查找进程7641的进程信息,但它只会报告父进程的ID:

 ps -o ppid= -p 7641 

我们被告知父进程 ID 是 7636。我们现在可以再次使用ps交叉引用它。

我们看到这与之前的父进程的名称相匹配。 要终止父进程,请在 kill 命令中使用 SIGKILL 选项,如下所示:

 杀死-SIGKILL 7636

根据父进程的所有者,您可能还需要使用sudo

僵尸并不可怕……

……除非他们是一大群人。 一些无需担心,简单的重新启动即可将它们清除。

广告

但是,如果您注意到某个应用程序或进程总是产生僵尸程序,那么您应该研究一下。 它很可能只是一个草率编写的程序,在这种情况下,也许有一个更新版本可以在其子进程之后正确清理。