Linux如何“杀死”进程?


91

尽管我一直从事计算机工作数十年,从事Linux已有十年,但实际上,我实际上将大多数OS功能视为黑匣子,这与魔术无异。

今天,我考虑了该kill命令,尽管我每天多次使用它(无论是“正常”还是“ -9味道”),但我必须承认我完全不知道它在后台如何工作。

从我的角度来看,如果正在运行的进程是“挂起”的,我会调用kill它的PID,然后突然不再运行。魔法!

那里到底发生了什么?联机帮助页谈论“信号”,但可以肯定,这只是一个抽象。发送kill -9到流程不需要流程的合作(例如处理信号),只是杀死了它。

  • Linux如何阻止进程继续占用CPU时间?
  • 是否已将其从计划中删除?
  • 它会断开进程与打开文件句柄的连接吗?
  • 进程的虚拟内存如何释放?
  • 内存中是否有类似全局表的内容,Linux保留对进程占用的所有资源的引用,而当我“杀死”进程时,Linux只是遍历该表并逐个释放资源?

我真的很想知道所有这些!


Answers:


71

向进程发送kill -9不需要进程的配合(例如处理信号),只是杀死了它。

您以为是因为可以捕获和忽略某些信号,所以它们都涉及合作。但是按照man 2 signal,“ 信号 SIGKILL和SIGSTOP不能被捕获或忽略”。可以捕获SIGTERM,这就是为什么plain kill并不总是有效的原因-通常,这意味着进程的处理程序中的某些内容出现了问题。1个

如果进程没有(或不能)为给定信号定义处理程序,则内核将执行默认操作。 对于SIGTERM和SIGKILL,这将终止进程(除非其pid为1;内核不会终止init2 表示其文件句柄已关闭,其内存返回到系统池,其父级接收SIGCHILD,其孤儿由init等继承,就像它已调用一样exit(请参阅参考资料man 2 exit)。该进程不再存在-除非它最终变成僵尸,否则在进程表中仍会列出一些信息;当它的父母没有wait并正确处理此信息。但是,僵尸进程不再分配任何内存,因此无法继续执行。

内存中是否有类似全局表的内容,Linux会保留对进程占用的所有资源的引用,而当我“杀死”进程时,Linux会简单地检查该表并逐个释放资源?

我认为这足够准确。物理内存按页面(通常一个页面等于4 KB块)进行跟踪,这些页面从全局池中取出并返回到全局池中。有点复杂,因为某些释放的页面会被缓存,以防再次需要包含它们的数据(即,从仍然存在的文件中读取的数据)。

联机帮助页谈论“信号”,但是可以肯定,这只是一个抽象。

当然,所有信号都是抽象的。它们是概念性的,就像“过程”一样。我在玩语义,但是如果您是说SIGKILL在质量上与SIGTERM不同,则是和否。是的,从某种意义上说,它无法被捕获,但是从某种意义上来说,它们既是信号,也没有。以此类推,一个苹果不是橙色,但按照先天的定义,苹果和橙子都是水果。SIGKILL似乎抽象,因为您无法捕获它,但这仍然是一个信号。这是SIGTERM处理的示例,我敢肯定您之前已经看过这些:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void sighandler (int signum, siginfo_t *info, void *context) {
    fprintf (
        stderr,
        "Recieved %d from pid %u, uid %u.\n",
        info->si_signo,
        info->si_pid,
        info->si_uid
    );
}

int main (void) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = sighandler;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGTERM, &sa, NULL);
    while (1) sleep(10);
    return 0;
}             

这个过程将永远休眠。您可以在终端中运行它,并通过发送给SIGTERM kill。它吐出类似的东西:

Recieved 15 from pid 25331, uid 1066.

1066是我的uid。该pid将是从其kill执行的shell 的pid,或者如果是fork(kill 25309 & echo $?),则为kill的pid 。

同样,没有必要为SIGKILL设置处理程序,因为它无法工作。3如果我kill -9 25309将终止该过程。但这仍然是一个信号。内核具有有关谁发送信号,它是哪种信号等信息。


1.如果尚未查看可能的信号列表,请参阅kill -l

2.正如Tim Post下文所述,另一个例外适用于不间断睡眠的过程。在解决根本问题之前,无法唤醒这些,因此在此期间将所有信号(包括SIGKILL)推迟。但是,流程无法故意造成这种情况。

3.这并不意味着kill -9在实践中使用更好。我的示例处理程序是不好的,因为它不会导致错误exit()。SIGTERM处理程序的真正目的是使进程有机会执行清理临时文件等操作,然后自愿退出。如果使用kill -9,则不会获得此机会,因此只有在“自愿退出”部分似乎失败的情况下,才这样做。


好的,但是杀死进程的是什么,-9因为那是真正的问题,谁会希望这个人死掉!;)
Kiwy 2014年

@Kiwy:内核。IPC包括通过它的信号;内核执行默认操作。
goldilocks 2014年

12
可能值得一提的是,当进程处于该状态时,磁盘睡眠(D)会抢占所有信号。因此,尝试对kill -9某些受I / O约束的进程将行不通,至少不会立即生效。
Tim Post

7
我要补充一点,由于kill -9无法捕获a,因此接收它的进程在退出之前无法执行任何清理(例如,删除临时文件,释放共享内存等)。因此,仅将kill -9(aka kill -kill)用作最后的手段。以a kill -hup和/或kill -term首先开始,然后kill -kill用作最后一击。
JRFerguson 2014年

实际上,“进程不再存在-除非它最终以僵尸身份出现,否则它仍会在内核的进程表中列出并包含一些信息”,实际上,所有进程在死亡时都会进入僵尸状态,而僵尸将在消失时消失父母确实对孩子稍加等待,通常情况发生得太快,以至于您看不到它的发生
聪明的2014年

3

每个进程都按计划的时间运行,然后被硬件计时器中断,以将其CPU内核用于其他任务。这就是为什么可能有比CPU核心更多的进程,甚至在一个核心CPU上运行带有许多进程的所有操作系统的原因。

进程中断后,控件返回到内核代码。然后,该代码可以做出不恢复被中断过程执行的决定,而无需过程侧的任何配合。kill -9可能最终在程序的任何行中执行。


0

这是关于终止进程如何工作的理想描述。实际上,任何Unix变体都会有许多其他的复杂性和优化。

内核具有用于每个进程的数据结构,该结构存储有关其映射的内存,具有的线程以及何时调度线程,已打开的文件等信息。如果内核决定终止某个进程,则会在其中进行注释进程的数据结构(可能在每个线程的数据结构中)将被杀死。

如果当前在另一个CPU上调度了进程的线程之一,则内核可能会在另一个CPU上触发中断,以使该线程停止更快地执行。

当调度程序注意到某个线程处于必须被杀死的进程中时,它将不再调度它。

当不再调度进程的线程时,内核将开始释放进程的资源(内存,文件描述符等)。每次内核释放资源时,它都会检查其所有者是否仍具有活动资源。一旦流程没有更多的活动资源(内存映射,打开的文件描述符等),就可以释放流程本身的数据结构,并可以从流程表中删除相应的条目。

某些资源可以立即释放(例如,释放I / O操作未使用的内存)。其他资源必须等待,例如,描述I / O操作的数据在I / O操作进行期间无法释放(正在进行DMA时,正在使用其访问的内存,并且取消DMA需要联系外围设备)。会通知此类资源的驱动程序,并可能试图加快取消速度;一旦不再进行该操作,驱动程序将完成该资源的释放。

(进程表中的条目实际上是属于父进程的资源,当进程终止并且父进程确认事件时,该资源将被释放。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.