有趣的僵尸进程和孤儿进程?
什么是僵尸进程?
当一个父进程创建了一个或多个子进程的时候,当子进程结束的时候,子进程的状态会变为Z状态,也就是僵尸状态。僵尸状态会以终止状态保存在进程表中,并且会等待父进程读取退出状态码。
说的直白点:举个例子,比如你的老师让你去干一件事(这里表示父进程创建子进程,让子进程去干事),然后你干完了,你是否要把这件事干的怎么样之类的结果告诉你的老师(表示子进程等待父进程读取退出的状态码)。这就是僵尸状态。
所以,当子进程退出,并且父进程还没有读取子进程的状态码时,子进程就会一直处在僵尸状态。
我们来举个例子来看一下:(该代码在Linux环境下运行)
#include <iostream>
#include <unistd.h>
int main(void)
{
std::cout << "Here is two process:" << std::endl;
pid_t id = fork();
if (id < 0)
{
return 1;
}
if (id == 0)//子进程
{
std::cout << "I am child ! My name is: " << getpid() << " My parent name is: " << getppid() << std::endl;
sleep(5);
}
else //父进程
{
std::cout << "I am Parent ! My name is: " << getpid() << " My parent name is: " << getppid() << std::endl;
//父进程一直循环造成子进程成为僵尸进程
while (true)
{}
}
return 0;
}
- 我们让子进程睡5秒,但是父进程一直死循环。所以当子进程退出的时候,父进程并没有可能读取子进程的退出码,所以子进程在5秒后会处于僵尸状态。
- 而我手动将父进程强制退出后,操作系统中就没有了Main这个进程了。为什么呢?那么到底谁来回收子进程呢?下面就会引出孤儿进程。
什么是孤儿进程?
当子进程的父进程退出了,并且没有读取子进程的退出码。那子进程是不是就没有父母了,不就成了孤儿。那么子进程肯定以某种方式退出了呀,不然怎么能看不到呢?
当子进程的父进程异常退出时并没有读取子进程的退出码对子进程进行回收。此时便由1号进程来领养该子进程,来读取它的退出码并回收它。
我们来用代码体现一下,看看现象:
int main(void)
{
std::cout << "Here is Orphan process !" << std::endl;
pid_t id = fork();
if (id < 0)
return 1;
if (id == 0)//子进程
{
while (true)
{
std::cout << "I am child ! My name is: " << getpid() << " My parent name is: " << getppid() << std::endl;
sleep(3);
}
}
else //父进程
{
std::cout << "I am parent ! My name is: " << getpid() << " My parent name is: " << getppid() << std::endl;
sleep(3);
}
return 0;
}
- 让父进程睡三秒后退出,然后让子进程一直不退出。看看1号进程会不会领养子进程。
- 可以很明显的看到,刚开始父进程和子进程都存在,现象很显然。
- 三秒后,父进程退出,而子进程并没有退出。然后子进程打印自己的父进程为1号进程。我们想看到的现象也就出来了。
僵尸进程的危害!?
- 如果父进程一直不读取子进程的退出码并对其进行回收的话,就像我们上面说的,子进程会一直等待并且存在于进程表中占用资源。
- 那么这样的僵尸进程如果越来越多,不就造成了可怕的内存泄漏问题。
怎么解决?
- 用信号的方式kill掉父进程,但是不推荐这种做法。如果父进程有重要的事情而非是个bug呢?直接kill掉会发生不明确行为。如果想kill掉子进程是没办法kill掉的。因为子进程已经是僵尸状态了,换句话就是说子进程已经死了,所以没办法kill掉。
- 进程等待。(以后会总结这部分知识)