向进程发送kill -9不需要进程的配合(例如处理信号),只是杀死了它。
您以为是因为可以捕获和忽略某些信号,所以它们都涉及合作。但是按照man 2 signal
,“ 信号 SIGKILL和SIGSTOP不能被捕获或忽略”。可以捕获SIGTERM,这就是为什么plain kill
并不总是有效的原因-通常,这意味着进程的处理程序中的某些内容出现了问题。1个
如果进程没有(或不能)为给定信号定义处理程序,则内核将执行默认操作。 对于SIGTERM和SIGKILL,这将终止进程(除非其pid为1;内核不会终止init
)2 表示其文件句柄已关闭,其内存返回到系统池,其父级接收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
,则不会获得此机会,因此只有在“自愿退出”部分似乎失败的情况下,才这样做。
kill -9
参考。