正常情况下,父进程创建子进程,子进程的结束和父进程的结束是异步过程,当一个子进程完成它的工作后,父进程需要调用 wait()
取得子进程的终止状态。
- 孤儿进程:父进程结束,子进程还在运行,那么这些子进程将成为孤儿进程,
init
进程完成对孤儿进程状态的收集。 - 僵尸进程:一个进程使用
fork
创建子进程,如果子进程退出,而父进程并没有调用wait()
获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。
当出现孤儿进程时,内核将把孤儿进程的父进程设置为 init
,有 init
进程负责收集孤儿进程的状态信息。
任何一个子进程( init
除外)在 exit()
之后,并非马上就消失掉,而是留下一个称为僵尸进程的数据结构,等待父进程处理。这是每个 子进程在结束时都要经过的阶段。如果子进程在 exit()
之后,父进程没有来得及处理,这时用 ps
命令就能看到子进程的状态是 Z
。
僵尸进程中保存着很多对程序员和系统管理员非常重要的信息,包括程序的退出码,进程占用的总系统CPU时间,发生页错误的数目和收到信号的数目。这些信息都被存储在僵尸进程中。进程退出后,系统会把该进程的状态变成僵尸,然后等待父进程来收集其退出信息,所以,使用僵尸状态表示进程退出了,正在等待父进程收集信息中。虽然僵尸进程并不占用系统资源,但是过多的僵尸进程也会影响系统的正常运行。首先,僵尸进程占用进程号,可能出现进程号不够用的情况。其次,进程表中包含过多僵尸进程的信息,会影响其他进程的正常运行。
杀死僵尸进程的方法:
- 找到父进程,杀死父进程,僵尸进程就变成孤儿进程,然后交给
init
进程接管 - 向父进程发送
SIGCHLD
信号,kill -s SIGCHLD pid
,该pid
是父进程的pid