概念
在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留在PCB中。直到父进程通过wait / waitpid来取时才释放。
正常情况下,父进程会收到两个返回值:exit code(SIGCHLD 信号)与 reason for termination 。之后,父进程会使用 wait(&status) 系统调用以获取子进程的退出状态,然后内核就可以从内存中释放已结束的子进程的 PCB;而如若父进程没有这么做的话,子进程的 PCB 就会一直驻留在内存中,一直留在系统中成为僵尸进程(Zombie)。
如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源。
- PID为0的进程为调度进程,该进程是内核的一部分,也称为系统进程;
- PID为1的进程为init进程,它是一个普通的用户进程,但是以超级用户特权运行;
- PID为2的进程是页守护进程,负责支持虚拟存储系统的分页操作。
进程 0 是系统引导时创建的一个特殊进程,也称之为内核初始化,
其最后一个动作就是调用 fork() 创建出一个子进程运行 /sbin/init 可执行文件,
而该进程就是 PID=1 的进程 1,而进程 0 就转为交换进程(也被称为空闲进程),
进程 1 (init 进程)是第一个用户态的进程,再由它不断调用 fork() 来创建系统里其他的进程,所以它是所有进程的父进程或者祖先进程。
同时它是一个守护程序,直到计算机关机才会停止。
危害
在Unix系统管理中,当用ps命令观察进程的执行状态时,经常看到某些进程的状态栏为defunct,这就是所谓的“僵尸”进程。“僵尸”进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。由于进程表的容量是有限的,所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数目太多,还会导致系统瘫痪。
僵尸进程的避免
- 父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。
- 可用signal函数为SIGCHLD安装handler,子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收。
- 如果父进程不关心子进程什么时候结束,那么可以signal(SIGCHLD,SIG_IGN)
通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。 - fork两次,父进程fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。