僵尸进程和孤儿进程简介
Posted on 2016-11-30 in Linux
前言
最近在做内部使用的 Docker base image,老大甩给我几个链接让我关注一下 Docker init process 的问题,其中有一篇文章详细描述了 Docker PID 1 僵尸程序回收的问题,我也趁此机会学习了一下有关僵尸进程和孤儿进程的知识。
基本概念
Linux 系统中运行的所有进程按照一颗树的形式组织。每个进程都可以生成子进程,并且除了最顶端的init
进程,每个进程都会有一个父进程。
当我们启动系统的时候,kernel
会启动最顶端的init
进程,然后由init
进程启动余下的部分,比如说SSH服务,Docker服务,Apache/Nginx,图形化界面等等,而它们又可以继续生成其他的子进程。
通常来说,当一个子进程退出的时候,父进程会收到操作系统发来的SIGCHLD
信号并且调用wait()
或者waitpid()
来取得子进程的终止状态,这个行为被叫做“回收(reaping)”。
但凡事总有例外。
比如说父进程在子进程退出之后并没有调用waitpid()
,又或者子进程仍在运行,而出于某些原因父进程退出了或者被终止了,这时候会出现什么情况?
- 孤儿进程(Orphan process):一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(PID 1)收养,并由init进程对它们完成状态收集工作。
- 僵尸进程(Zombie process):一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait()或者waitpid()获取子进程的状态信息,那么子进程的进程描述符仍然保留再系统中。这种进程称之为僵尸进程。
危害
对于孤儿进程,由于它会被init进程接管并处理后续工作,因此并不会有什么危害。
而对于僵尸进程,参考Linux waitpid man page:
"As long as a zombie is not removed from the system via a wait, it will consume a slot in the kernel process table, and if this table fills, it will not be possible to create further processes."
也就是说,如果父进程不调用 wait/waitpid 的话,即使子进程所占用的内存空间已经被释放,它在进程表中保留的信息却没有释放,其进程号会一直被占用,但是系统所能使用的进程号是有限的,如果产生大量的僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程。