Linux 中的 kill 命令:如何安全停止无响应的进程

Linux 系统虽然稳定,但应用程序仍可能卡死。一旦出现这种情况,卡住的进程会持续运行并耗尽 CPU 或内存,拖慢整个系统。重启固然有效,但在生产服务器上既缓慢又影响业务。正因如此,Linux 中的 kill 命令是管理员必备的关键工具。

当程序挂起时,Linux 仍将其视为活动进程。您无需重启所有服务,只需针对出问题的进程即可。Linux 中的 kill 命令会向该进程发送信号并将其停止,帮助您以最小的影响快速恢复系统稳定。

进程与进程 ID(PID)

进程是系统中正在运行的程序实例。每个进程在启动时都会被分配一个唯一的进程 ID,即 PID。进程结束后,其 PID 会被释放,之后可能被系统重新使用。如果您想精准定位并停止出现故障的应用程序,知道其 PID 至关重要。

Linux 提供了多种内置工具来查找 PID。top 命令会实时显示所有活动进程及其资源占用情况,便于发现有问题的进程。另一种常用方法是 ps 命令,它可以搭配不同选项进行过滤,帮助您在安全、高效地终止 Linux 进程之前准确找到目标进程:

[root@host ~]# ps faux | grep systemd
root 1 0.0 0.6 96656 11260 ? Ss Jan24 0:08 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
root 533 0.0 1.3 125588 22832 ? Ss Jan24 0:25 /usr/lib/systemd/systemd-journald
root 564 0.0 0.5 107440 9248 ? Ss Jan24 0:00 /usr/lib/systemd/systemd-udevd
Dbus 684 0.0 0.3 73540 5524 ? Ss Jan24 0:06 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root 743 0.0 0.4 95736 7760 ? Ss Jan24 0:01 /usr/lib/systemd/systemd-logind
root 66199 0.0 0.0 12108 1060 pts/0 S+ 08:28 0:00 \_ grep --color=auto systemd
root 66153 0.0 0.5 93212 9472 ? Ss 08:27 0:00 /usr/lib/systemd/systemd --user
[root@host ~]#
[root@host ~]# ps -eo user,pid,command | grep systemd
root 1 /usr/lib/systemd/systemd --switched-root --system --deserialize 18
root 533 /usr/lib/systemd/systemd-journald
root 564 /usr/lib/systemd/systemd-udevd
dbus 684 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root 743 /usr/lib/systemd/systemd-logind
root 66153 /usr/lib/systemd/systemd --user
root 66213 grep --color=auto systemd
[root@host ~]#

您还可以使用 pidof process_name 或 pgrep process_name 命令查找 PID,两者都能快速返回与指定应用名称对应的进程 ID:

[root@host ~]# pidof systemd
66156 66153 1
[root@host ~]#
[root@host ~]# pgrep systemd
1
533
564
743
66153
[root@host ~]#

要停止失控的程序,管理员通常依靠 Linux kill 命令。这个内置工具会向指定的 PID(或作业)发送信号,使操作系统能够结束、暂停或恢复目标进程。如果您想知道如何在 Linux 中终止进程,第一步始终相同:先找到 PID,再使用 Linux kill 命令发送相应的信号。

理解 kill 信号

信号是由内核、其他进程或进程自身发送给某个进程的简短消息。每个信号都有预定义的动作(处置方式),例如:

Term:终止
Ign:忽略
Core:终止并生成 core dump
Stop:暂停执行
Cont:恢复执行

大多数情况下,Linux kill 命令会先发送正常终止请求,只有在进程拒绝停止时才升级处理。Linux 最多支持 64 个信号:1 至 31 为标准信号,其余为实时信号。标准信号不会排队,而实时信号会排队并按顺序传递。

要列出信号及其编号,请运行 kill -l 或查看 man 7 signal。理解信号有助于您正确使用 Linux kill 命令,尽量减少对系统的干扰,并干净利落地处理卡住的进程。

运行 kill -l 或查阅信号手册 man 7 signal,即可获得完整的信号列表:

[root@host ~]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 
7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 
29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 
36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 
40) SIGRTMIN+641) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 
44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-1451) SIGRTMAX-13 
52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 
56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 
60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 
64) SIGRTMAX
[root@host ~]#

许多信号都有默认动作,但程序可以通过定义处理函数(即“捕获”信号)来覆盖它。如果进程没有处理函数,则采用默认行为;对于某些信号,这可能意味着信号被忽略。有两个例外:SIGKILL 和 SIGSTOP,它们无法被捕获、阻塞或忽略。SIGTERM 可以被处理或忽略,因此顽固的应用程序在收到 SIGTERM 请求后可能依然存活。此时您可以升级处理,发送 SIGKILL 立即结束它。请谨慎使用 SIGKILL,因为它会阻止进程执行清理工作,可能留下临时文件。

在下面的示例中,kill -15 未能生效,因此 Linux 强制终止了进程:

[root@host ~]# ps -eo user,pid,command | grep java
tomcat 59815 /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat9/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/tomcat9/bin/bootstrap.jar:/usr/local/tomcat9/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat9 -Dcatalina.home=/usr/local/tomcat9 -Djava.io.tmpdir=/usr/local/tomcat9/temp org.apache.catalina.startup.Bootstrap start
root 66401 grep --color=auto java
[root@host ~]# kill -15 59815
[root@host ~]#

如何使用 Linux kill 命令?

Linux kill 命令可以向进程发送信号,并遵循一些重要的权限与 PID 规则。一般来说,普通用户只能向自己拥有的进程发送信号,而 root 用户可以向系统中的任何进程发送信号。

Linux kill 命令的行为取决于您提供的 PID(或类似 PID 的值):

PID > 0:将所选信号发送给具有该 PID 的单个进程。
PID = 0:作用于当前 shell 进程组(PGID)中的所有进程。
PID = -1:作用于与执行命令的用户具有相同用户 ID 的所有进程(请谨慎使用)。
PID < -1:作用于 PGID 等于该数值绝对值的进程组。

Linux kill 命令的语法和基本用法是什么?

默认情况下,Linux kill 命令发送 SIGTERM,请求程序正常关闭,并给它执行清理的机会。如果进程忽略或处理了 SIGTERM 并继续运行,您可以改用其他信号重试。

您可以用多种格式指定信号:

使用编号:kill -9 <PID>
带 SIG 前缀:kill -SIGKILL <PID>
不带 SIG 前缀:kill -KILL <PID>

实际操作中,通常先使用 SIGTERM,只有在必要时才升级。例如,如果 kill -15 <PID> 无法停止卡住的 Java 进程,使用 kill -9 <PID>(SIGKILL)即可强制立即终止。Linux kill 命令功能强大,因此应谨慎使用较强的信号,尤其是在影响进程组或多个正在运行的进程时:

[root@host ~]# ps -eo user,pid,command | grep java
tomcat 66469 /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat9/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/tomcat9/bin/bootstrap.jar:/usr/local/tomcat9/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat9 -Dcatalina.home=/usr/local/tomcat9 -Djava.io.tmpdir=/usr/local/tomcat9/temp org.apache.catalina.startup.Bootstrap start
root 66516 grep --color=auto java
[root@host ~]# kill -9 66469
[root@host ~]# 
[root@host ~]# ps -eo user,pid,command | grep java
root 66530 grep --color=auto java
[root@host ~]#

使用 Linux kill 命令时,请遵循以下语法:

kill [OPTIONS] [PID]

例如,如果某个 httpd 进程的 PID 为 21567,您可以发送默认的 TERM 信号,请求其正常关闭:

kill 21567

如果进程仍未停止,您可以使用 SIGKILL 强制终止(不进行清理,也不等待):

kill -9 21567
kill -SIGKILL 21567
kill -KILL 21567

如何按进程 ID 终止进程

要停止某个应用程序,首先需要知道它的进程 ID,即 PID。最快捷的方法之一是用 ps 列出正在运行的进程,并按名称过滤输出。例如,查找 Firefox:

ps aux | grep firefox

确认 PID 正确后,您可以发送 SIGKILL 立即终止该进程:

kill -9 PID

如何同时终止多个进程

如果多个相关进程出现异常,您可以在一条命令中提供多个 PID,一次性将它们全部停止:

kill -9 PID_1 PID_2 PID_3

如何使用 Linux kill 命令发送特定信号

Linux kill 命令使用以下通用语法向进程发送信号:

kill [signal] PID

信号可以用三种常见格式指定:

  • 使用编号(信号 ID)
  • 带 SIG 前缀
  • 不带 SIG 前缀

要查看所有可用信号及其编号,请运行:

kill -l

1)使用编号指定信号

SIGKILL 是 9 号信号,因此要强制停止 PID 9338:

kill -9 9338

2)使用带 SIG 前缀的名称指定信号

使用 SIG 名称执行相同操作:

kill -SIGKILL 9338

3)使用不带 SIG 前缀的名称指定信号

您也可以省略 SIG,直接使用信号名称:

kill -KILL 9338

如何使用 SIGTERM 正常终止进程

如果您希望干净地关闭进程,请使用 SIGTERM(15)。SIGTERM 会请求进程退出,并给它时间妥善释放资源。当进程忽略 SIGTERM 或无法停止时,您可以升级为 SIGKILL,它会立即强制终止进程,且不允许执行清理。

Linux kill 命令的高级技巧

在处理顽固或重复性任务时,Linux kill 命令并不是唯一的选择。pkill 和 skill 等工具可以加快进程控制,尤其适用于按名称而非 PID 定位进程的场景。

使用 pkill 按名称停止进程

pkill 会向符合条件的进程发送信号,这些条件包括完整或部分进程名、进程所属用户或其他属性。如果不带选项运行,它默认向所有匹配的进程发送 SIGTERM(15)。例如,要正常停止所有 Firefox 进程,请使用:

pkill -15 firefox

由于 pkill 支持模式匹配,因此不需要提供确切的进程名。例如,如果您想停止 httpd,并且知道其名称中包含“http”,可以运行:

pkill http

这种方法会查找名称与模式匹配的所有正在运行的进程,并请求终止它们。请谨慎使用宽泛的模式,以免误停无关的服务。

关于 skill 的更多说明

“skill”是另一个发送信号的工具,目标与上述命令类似。它沿用常见的信号行为,通常默认发送 SIGTERM,因此在需要按匹配规则进行选择性定位(例如按用户过滤或按进程组条件)时,适合用于标准的正常关闭:

skill [signal] [options]
[root@host ~]# ps -eo user,pid,command | grep tomcat
tomcat 66546 /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat9/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -classpath /usr/local/tomcat9/bin/bootstrap.jar:/usr/local/tomcat9/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat9 -Dcatalina.home=/usr/local/tomcat9 -Djava.io.tmpdir=/usr/local/tomcat9/temp org.apache.catalina.startup.Bootstrap start.
root 66846 grep --color=auto tomcat
[root@host ~]# skill -9 66546

建议使用 kill、pkill 或 killall 命令来代替 skill。

如何使用 killall 按名称终止多个进程

killall 是一款 Linux 命令行工具,它根据可执行文件名称而非 PID 来结束进程。当某个应用程序生成了多个相同的工作进程,而您希望一并停止它们时,这种方式非常方便,无需手动逐个查找进程 ID。

基本语法如下:

$ killall process_name

例如,要请求正常关闭所有 Firefox 实例,请使用:

$ killall firefox

默认情况下会发送终止信号(SIGTERM),让程序有机会关闭文件、释放锁并正常退出。当进程卡死或忽略 SIGTERM 时,可以指定更强的信号强制其立即停止:

$ killall -s SIGKILL firefox

信号也可以用编号指定。在 Apache 服务以 httpd 进程名运行的系统上,下面的命令会强制停止 Apache:

$ killall -9 httpd

名称匹配的工作方式与常见错误

名称匹配是精确匹配,只有名称与参数完全相同的进程才会被定位。由于 Apache 通常使用 httpd 而不是 http,下面的命令通常会返回不存在该进程的错误:

$ killall http

在发送具有破坏性的信号之前,请使用 ps 或 pgrep 核实真实的进程名,以免漏掉目标或误停其他服务。

如何使用 killpg 向整个进程组发送信号

有时您需要影响由同一会话启动的一整组相关进程。killpg 命令会向指定进程组(pgrp)中的每个进程发送信号。如果 pgrp 为 0,信号将发送到调用者当前所在的进程组;否则,该组中的所有进程都会收到信号。

这种方法非常适合清理工作,但在生产环境中务必仔细核对匹配模式。

将 kill 与 ps 和 grep 搭配使用

ps 命令会显示正在运行的内容,包括进程名、PID、所有者和状态,帮助您在使用 kill 发送信号之前确认目标应用程序是否正确。为了避免翻阅长长的列表,可以使用 grep 过滤输出,快速找到正确的进程和 PID,降低误杀其他进程的风险。

处理无响应的进程

Linux 进程可能处于不同状态,包括运行(R)、可中断睡眠(S)、不可中断睡眠(D)、已停止(T)和僵尸(Z)。处于 D 状态或显示为 Z 的进程通常需要关注。您可以使用以下命令按状态过滤:

ps aux | awk '{if ($8=="D") print}'

该命令只输出处于不可中断睡眠状态的进程,这可能表明进程正在等待 I/O 或内核级操作。

管理其他用户拥有的进程

普通用户只能终止自己拥有的进程。如果您是系统管理员,需要停止属于其他账户的进程,请使用 sudo 提升权限运行命令,或以 root 身份操作。

何时应该强制终止?

如果 SIGTERM 无法停止应用程序,SIGKILL 会立即将其结束。由于 SIGKILL 无法被捕获、阻塞或忽略,只有在正常终止的尝试失败后才应使用它。

Linux 中的高级进程控制命令与技巧

除了标准的进程终止工具,Linux 还提供了大量面向特定环境的高级命令,适用于数据库、容器、网络、图形界面和分布式系统等场景。当传统的进程管理方法不够用时,这些工具尤其有用。

1. 了解 mysql_zap 命令

mysql_zap 命令用于终止 ps 命令输出行与特定模式相匹配的 Linux 进程。只要模式出现在进程 ps 输出中的任意位置,该进程即视为匹配。与许多终止工具一样,除非明确指定其他信号,mysql_zap 默认发送 SIGTERM 信号。

语法:

[root@host ~]# mysql_zap [signal] [pattern]

需要注意的是,从 MariaDB 10.2 版本开始,mysql_zap 已被弃用。作为现代且受支持的替代方案,建议管理员使用 pkill,它提供了类似的模式匹配功能。

2. 使用 mk-kill 管理 MySQL 查询

mk-kill 命令侧重于数据库层面的控制,而不是系统进程。它用于终止符合特定条件的 MySQL 查询。如果提供了文件,mk-kill 会从该文件读取查询数据,文件内容通常是 SHOW PROCESSLIST 的输出。如果未提供文件,它会自动对 MySQL 服务器执行 SHOW PROCESSLIST。

示例:

[root@host ~]# mk-kill --busy-time 60 --print
[root@host ~]# mk-kill --match-command Sleep --kill --no-only-oldest --interval 10

第一个示例找出运行时间超过 60 秒的查询。第二个示例每 10 秒检查一次处于休眠状态的查询,并终止发现的所有此类查询。这使 mk-kill 在保持数据库响应能力方面尤为有用。

3. 使用 mkill 终止慢查询

mkill 命令与 mk-kill 密切相关,用于停止运行缓慢的 MySQL 查询。它会根据多项条件评估查询,包括:

  • 查询执行时间
  • 主机
  • 用户
  • 数据库
  • 查询状态
  • 查询内容

该命令常用于自动化的数据库性能管理。

4. 使用 tkill 和 tgkill 终止单个线程

在终止单个线程比停止整个进程更合适的场景中,Linux 提供了 tkill 和 tgkill。tkill 命令已被弃用,它仅通过线程 ID 识别线程,如果线程 ID 被重复使用,可能导致误终止。

tgkill 命令要求同时提供线程 ID 和线程组 ID(TGID),从而确保信号发送给正确的线程,安全性更高。

5. 使用 killpg 向进程组发送信号

killpg 命令会向整个进程组发送信号。如果进程组 ID 设为 0,信号将发送到调用者所在的进程组;否则,信号会传递给与指定进程组关联的所有进程。这种方法适用于停止在同一会话中启动的相关后台作业。

6. 使用 tcpkill 终止活动的 TCP 连接

tcpkill 命令允许管理员中断活动的 TCP 连接。它可以监听指定的网络接口,并在终止连接时采用不同的强度级别。默认强度级别为 3。

语法:

[root@host ~]# tcpkill [-i interface] [-1...9] expression
[root@host ~]# tcpkill -i eth0 port 21

该工具常用于立即断开有问题或未经授权的网络会话。

7. 使用 lxc-kill 停止容器化进程

在使用 LXC、Kubernetes 或 Ubuntu 上的 Docker 等容器化环境时,可以使用 lxc-kill 命令向容器内的主进程发送数字信号。

语法:

lxc-kill --name=NAME SIGNUM

这让您可以直接控制容器的生命周期和进程终止。

8. 使用 arckill 管理分布式作业

arckill 命令用于启用 ARC 的网格计算环境。ARC(Advanced Resource Connector)为在分布式系统中提交和管理计算作业提供了统一的接口。作业可以通过作业 ID 或提交时的作业名称来终止。

示例:

arckill -j filename.xml (<jobid#>)

9. 使用 pvm_kill 终止 PVM 进程

要在并行虚拟机(PVM)环境中停止特定进程,pvm_kill 命令会向通过任务 ID(TID)识别的进程发送终止信号。该命令通常在大型应用程序内部调用。

示例:

In C: info = pvm_kill( tid );
In Fortran: CALL PVMFKILL( TID, INFO )

10. 使用 xkill 关闭卡死的 GUI 应用程序

xkill 命令提供了一种以图形方式终止无响应应用程序的方法。在桌面环境中执行该命令后,光标外观会发生变化,您可以点击卡死的窗口,随后 X 服务器会立即终止相关程序。

语法:

xkill [-display displayname] [-id resource] [-button number] [-frame] [-all]

当图形应用程序停止响应且无法正常关闭时,这个命令尤其有用。

终止进程的注意事项与最佳实践

停止进程并不总是一次干净的重置。如果应用程序正在写入磁盘、持有锁、运行活动会话或与其他服务协同工作,突然停止可能会留下损坏的临时数据、残留的锁文件、未完成的事务或孤立的子进程。请将终止进程视为一种受控的干预,而不是条件反射:确认 PID 正确,了解该服务的作用,除非您已准备好应对登录失败、网络问题或停机等副作用,否则不要动系统关键守护进程。只要条件允许,请先使用正常关闭的信号,只有在进程明显卡死时才升级处理。

结论

终止进程更像是手术刀,而不是锤子。操作得当,无需重启就能快速解决问题;操作草率,则可能引发更大的麻烦。关键在于以正确的方式停止正确的进程,并在之后保持系统稳定。

blog