经典面试题:孤儿进程、僵尸进程、守护进程详解
孤儿进程、僵尸进程、守护进程,是非常常见的 Linux 面试题。本文就来详细介绍下这三个进程的定义和区别。
孤儿进程是指其父进程已经终止或不存在,但是该进程仍在继续运行的进程。
如果父进程先退出,子进程还没退出那么子进程将被托孤给 init 进程,这时子进程的父进程就是 init 进程(1 号进程)。init 进程完成所有孤儿进程的状态收集工作。即每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init,而 init 进程会循环地 wait() 它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init 进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。
僵尸进程僵尸进程是指一个子进程已经终止,但其父进程尚未调用 wait() 或 waitpid() 系统调用来获取子进程的终止状态,导致子进程的进程描述符仍然存在,此时子进程将成为一个僵尸进程。
一个进程在调用 exit 命令结束自己的生命的时候,其实它并没有真正的被销毁, 而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用 exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)
在 Linux 进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD 信号处理函数调用 wait 或 waitpid() 等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么 init 进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
系统所能使用的进程号是有限的,如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。 此即为僵尸进程的危害,应当避免。
(1) 子进程结束后为什么要进入僵尸状态?
因为父进程可能要取得子进程的退出状态等信息。
(2) 僵尸状态是每个子进程必经的状态吗?
是的。任何一个子进程(init 除外)在 exit() 之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在 exit()之后,父进程没有来得及处理,这时用 ps 命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用 ps 命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。如果父进程在子进程结束之前退出,则子进程将由 init 接管。init 将会以父进程的身份对僵尸状态的子进程进行处理。
(3) 如何查看僵尸进程?
ps -el 其中,有标记为 Z 的进程就是僵尸进程 S 代表休眠状态;D 代表不可中断的休眠状态;R 代表运行状态;Z 代表僵死状态;T 代表停止或跟踪状态。
在 fork() / execve() 过程中,假设子进程结束时父进程仍存在,而父进程 fork() 之前既没安装 SIGCHLD 信号处理函数调用 waitpid() 等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是 root 身份 kill -9 也不能杀死僵尸进程。
(4) 如何解决僵尸进程?
杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为"孤儿进程",过继给 1 号进程 init,init 始终会负责清理僵尸进程。
守护进程守护进程( daemon) 是指在后台运行,没有控制终端与之相连的进程。它独立于控制终端,通常周期性地执行某种任务 。 守护进程脱离于终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的终端信息所打断。
总结孤儿进程是父进程终止后仍在运行的进程,由init进程接管管理;僵尸进程是子进程已经终止但父进程未处理其终止状态的进程,会占用系统资源;守护进程是在后台运行的独立进程,通常用于执行系统任务或服务。