一个进程使用 fork
创建子进程,如果子进程退出,而父进程没有调用 wait
或 waitpid
函数获取子进程的状态信息,那么子进程的进程描述符仍然会保存在系统中,这种进程称为僵尸进程。
在子进程退出时,如果父进程不调用 wait
或 waitpid
函数的话,那么系统保留的子进程的信息就不会被释放,其子进程号会一直被占用,但是系统所能使用的进程号是有限的,如果产生大量的僵尸进程,最终可能导致系统没有可用的进程号,从而不能产生新的进程。
例如有个进程,它定期的产生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短,但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问,这样系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用 ps
命令查看的话,就会看到很多状态为 Z(defunct)的进程。 严格地来说,僵尸进程并不是问题的根源,罪魁祸首是产生出大量僵尸进程的那个父进程。
因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大量僵尸进程的那个元凶枪毙掉(也就是通过 kill
发送 SIGTERM
或者 SIGKILL
信号)。枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进程,这些孤儿进程会被 init
进程接管,init
进程会 wait
这些孤儿进程,释放它们占用的系统进程表中的资源,这样,这些已经僵死的孤儿进程 就能瞑目而去了。
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被 init
进程(进程号为1)所收养,并由 init
进程对它们完成状态收集工作。由于孤儿进程会被 init
进程给收养,所以孤儿进程不会对系统造成危害。
守护进程,也就是通常说的 Daemon 进程,是 Linux 中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是脱离于终端并且在后台运行的进程。守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。