Linux - 为什么有时候kill -9无法杀掉进程

2022年03月21日 14:03:31    [原创]

在Linux中,我们经常使用kill或者kill -9来杀死特定的进程,但是有些时候,这些方法可能无法终止某些进程。本文将详细解释为什么会出现这种情况,以及如何处理这种问题。


1:进程在内核态执行:

当进程在执行系统调用或陷入内核态时,它可能暂时无法响应用户空间的信号。虽然kill -9发送的SIGKILL信号最终会被进程接收到,但在进程从内核态返回到用户态之前,这个信号可能不会立即生效。

这种情况通常会在进程执行I/O操作、系统调用或陷入内核态时发生。


2:进程被挂起(Stopped):

如果一个进程已经被挂起(通过SIGSTOP、SIGTSTP等信号),那么它将无法接收任何信号,包括kill -9发送的SIGKILL信号。在这种情况下,需要先使用SIGCONT信号恢复进程的运行状态,然后再尝试使用kill -9。挂起状态通常发生在调试过程中,当使用调试器如gdb时,进程会被挂起以进行调试。


3:进程在执行原子操作:

当进程在执行原子操作(如原子读写、原子更新等)时,它可能暂时无法响应信号。虽然kill -9发送的SIGKILL信号最终会被进程接收到,但在原子操作完成之前,这个信号可能不会立即生效。

原子操作通常在多线程或并发编程中使用,以保证数据的一致性和完整性。


4:进程在执行临界区代码:

当进程在执行临界区代码(如访问共享资源、执行互斥操作等)时,它可能暂时无法响应信号。虽然kill -9发送的SIGKILL信号最终会被进程接收到,但在临界区代码执行完毕之前,这个信号可能不会立即生效。

临界区代码通常在多线程或并发编程中使用,以保证资源的互斥访问和数据的一致性。


5:进程在执行不可中断的睡眠:

当进程在执行不可中断的睡眠(如等待磁盘I/O完成)时,它可能暂时无法响应信号。虽然kill -9发送的SIGKILL信号最终会被进程接收到,但在不可中断的睡眠状态结束之前,这个信号可能不会立即生效。

不可中断的睡眠状态通常在进程等待I/O操作完成时发生,如读取磁盘、网络通信等。


6:权限问题:

如果进程具有较高的权限,如root权限,而执行kill -9命令的用户权限较低,那么可能无法终止该进程。在这种情况下,需要使用具有足够权限的用户或使用sudo命令来执行kill -9命令。

但是,即使使用sudo命令,也无法终止内核进程或某些特殊状态的进程。


7:进程状态:

如果进程处于某些特殊状态,如死锁状态或僵尸状态,那么kill -9命令可能无法立即终止进程。在这种情况下,可能需要先解决进程的状态问题,如解除死锁或清理僵尸进程,然后再尝试终止进程。这个很好理解,僵尸进程其实已经不占用任何系统资源,本质上已经结束了只剩下一个结构体空壳,没有执行任何代码的能力,所以也无法处理任何信号。


8:进程被systemd自动拉起:

进程被systemd管理,且Restart设为on-failure时,on-failure 表示 仅在服务进程异常退出时重启,所谓"异常退出" 是指: 退出码不为"0", 或者 进程被强制杀死(包括 "core dump"以及收到 SIGHUP, SIGINT, SIGTERM, SIGPIPE 之外的其他信号), 或者进程由于 看门狗超时 或者 systemd 的操作超时 而被杀死。 这时候进程会因为退出码不为0(被强制杀死)而被systemd自动拉起,所以即使你执行了kill -9也无法杀掉该进程,因为杀掉后会被systemd立即重新拉起。


最后,生产环境中要慎用kill -9,不到非不得已不要使用它。 因为进程都有自己完整的退出逻辑,退出过程中会进程很多处理,比如保存数据,释放资源,释放锁等,如果强行杀掉可能会导致很多问题,比如数据没来及的保存导致丢失,资源没释放导致潜在的内存泄漏风险,甚至文件的损坏。如果一定要强行结束进程更推荐和更安全的做法是使用pkill 命令,可以安全的结束指定程序的所有相关联进程,避免某些关联进程没有结束导致整个进程无法结束的情况。