就像实际的僵尸一样,僵尸进程无法杀死,因为它已经死了。
怎么发生的
在Linux / Unix中,当进程死亡/结束时,该进程中的所有信息将从系统内存中删除,只有进程描述符保留。进程进入状态Z(僵尸)。他的父进程从内核获取信号:SIGCHLD
,这意味着他的一个子进程退出,被中断或在被中断后恢复(在我们的情况下,它只是退出)。
现在,父进程需要执行wait()
syscall才能从其子进程中读取退出状态和其他信息。然后将描述符从内存中删除,该过程不再是僵尸。
如果父进程从未调用过wait()
syscall,则僵尸进程描述符将保留在内存中并吞噬大脑。通常您不会看到僵尸进程,因为上述过程花费的时间更少。
死者的黎明
每个进程描述符都需要非常少量的内存,因此一些僵尸并不是很危险(就像在现实生活中一样)。一个问题是每个僵尸进程都保留其进程ID,而Linux / Unix操作系统的pid数量有限。如果编程不当的软件生成了很多僵尸进程,则可能由于不再有可用的进程ID而无法启动进程。
因此,如果他们成群结队,那就非常危险(就像在许多电影中都很好地展示了)
我们如何捍卫自己免受僵尸大军的袭击?
头部射击会起作用,但是我不知道该命令(SIGKILL无法起作用,因为该过程已经死了)。
好了,您可以通过kill将SIGCHLD发送给父进程,但是当它忽略此信号时,该怎么办?您唯一的选择是杀死父进程,并且初始化进程“采用”僵尸。Init定期wait()
调用syscall清理他的僵尸孩子。
就你而言
就您而言,您必须将SIGCHLD发送到crond进程:
root@host:~# strace -p $(pgrep cron)
Process 1180 attached - interrupt to quit
然后从另一个终端:
root@host:~$ kill -17 $(pgrep cron)
输出为:
restart_syscall(<... resuming interrupted call ...>) = ? ERESTART_RESTARTBLOCK (To be restarted)
--- SIGCHLD (Child exited) @ 0 (0) ---
wait4(-1, 0x7fff51be39dc, WNOHANG, NULL) = -1 ECHILD (No child processes) <-- Here it happens
rt_sigreturn(0xffffffffffffffff) = -1 EINTR (Interrupted system call)
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=1892, ...}) = 0
rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
rt_sigaction(SIGCHLD, NULL, {0x403170, [CHLD], SA_RESTORER|SA_RESTART, 0x7fd6a7e9d4a0}, 8) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
nanosleep({42, 0}, ^C <unfinished ...>
Process 1180 detached
您会看到wait4()
syscall返回-1 ECHILD,这意味着那里没有子进程。因此得出的结论是:cron对SIGCHLD系统调用做出反应,不应强制使用启示录。