令我感到困惑的是,尽管我从事计算机工作已经有几十年了,而从事Linux的工作已经有十年了,但实际上,我将大多数OS功能视为一个黑匣子,与魔术无异。我考虑过kill命令,虽然我每天多次使用它(无论是“正常”还是-9口味),但我必须承认我完全不知道它在后台如何工作。

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

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


Linux如何阻止进程继续占用CPU时间?
是否将其从调度中删除?
它是否断开进程与打开文件句柄的连接?
进程的虚拟内存如何释放?
是否有全局变量?内存中的表,Linux保留对进程占用的所有资源的引用,当我“杀死”进程时,Linux会简单地遍历该表并通过以下方式释放资源一个?

我真的很想知道这一切!

评论

必杀-9参考。

我的关于SIGKILL的问题的答案在这里也可能与此相关。

#1 楼


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


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

如果进程未(或无法)定义对于给定信号的处理程序,内核执行默认操作。对于SIGTERM和SIGKILL,这将终止进程(除非其PID为1;内核将不会终止init)2,这意味着其文件句柄已关闭,其内存返回到系统池,其父级接收到SIGCHILD,孤儿是由init等继承的,就像它被称为exit一样(请参阅man 2 exit)。该进程不再存在-除非它最终变成僵尸,否则在内核的进程表中仍会列出该进程以及一些信息;如果其父项没有正确处理此信息,则会发生这种情况。但是,僵尸进程不再为它们分配任何内存,因此无法继续执行。一个进程,而当我“杀死”一个进程时,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,
        "Received %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;
}


此过程将永远休眠。您可以在终端中运行它,并使用wait将其发送给SIGTERM。它吐出类似以下内容的东西:

Received 15 from pid 25331, uid 1066.


1066是我的UID。 PID将是执行kill的外壳的PID,或者是如果您对其进行分叉(kill)的kill的PID。 t work.3如果我kill 25309 & echo $?,该过程将终止。但这仍然是一个信号。内核具有有关谁发送信号,信号是什么的信息,等等。


1。如果您尚未查看可能的信号列表,请参阅kill -9 25309

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

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

评论


好的,但是用-9杀死进程的原因是,这是一个真正的问题,是谁会希望这个人死掉! ;)

–奇威
2014年1月30日10:41

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

–金锁
2014年1月30日10:46

可能值得一提的是,在该状态下,磁盘睡眠(D)会抢占所有信号。因此,试图杀死-9个特定的I / O绑定进程将无法正常工作,至少不会立即生效。

– Tim Post
2014年1月30日,11:21



我要补充一点,因为无法捕获kill -9,所以接收它的进程在退出之前无法执行任何清理(例如,删除临时文件,释放共享内存等)。因此,只能将kill -9(也称为kill -kill)作为最后的手段。首先执行kill -hup和/或kill -term,然后使用kill -kill作为最后一击。

– JRFerguson
2014年1月30日12:41

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

–聪明
2014年2月1日在6:35



#2 楼

每个进程都按计划的时间运行,然后被硬件计时器中断,以将其CPU内核用于其他任务。这就是为什么可能有比CPU核心更多的进程,甚至可能在一个核心CPU上运行带有许多进程的所有操作系统的原因。
中断该进程后,控制权返回到内核​​代码。然后,该代码可以做出不恢复被中断过程执行的决定,而无需过程侧的任何配合。 kill -9可能最终在程序的任何行中执行。

#3 楼

这是关于终止进程如何工作的理想描述。实际上,任何Unix变体都会带来许多其他复杂性和优化。如果内核决定终止某个进程,则它会在进程的数据结构(甚至可能是每个线程的数据结构)中记录要终止的进程。

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

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

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

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