kill
命令,虽然我每天多次使用它(无论是“正常”还是-9
口味),但我必须承认我完全不知道它在后台如何工作。从我的角度来看,如果正在运行的进程“挂起”,我会在其PID上调用
kill
,然后突然不再运行。魔术!那里到底发生了什么?联机帮助页谈论“信号”,但是可以肯定,这只是一个抽象。将
kill -9
发送到进程并不需要进程的配合(例如处理信号),只是杀死了它。Linux如何阻止进程继续占用CPU时间?
是否将其从调度中删除?
它是否断开进程与打开文件句柄的连接?
进程的虚拟内存如何释放?
是否有全局变量?内存中的表,Linux保留对进程占用的所有资源的引用,当我“杀死”进程时,Linux会简单地遍历该表并通过以下方式释放资源一个?
我真的很想知道这一切!
#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时需要联系外围设备)。会通知此类资源的驱动程序,并可能试图加快取消速度;一旦操作不再进行,驱动程序将完成该资源的释放。
(进程表中的条目实际上是属于父进程的资源,当进程终止并且父进程确认该事件时,该资源将被释放。)
评论
必杀-9参考。我的关于SIGKILL的问题的答案在这里也可能与此相关。