

🎁个人主页: 工藤新一¹
🔍系列专栏: C++面向对象(类和对象篇)
🌟心中的天空之城,终会照亮我前方的路
🎉欢迎大家点赞👍评论📝收藏⭐文章
文章目录
- [进程状态 --- 僵尸进程](#进程状态 — 僵尸进程)
-
- [一、进程状态 --- Zombies](#一、进程状态 — Zombies)
- 二、僵尸进程
-
- [2.1 什么是僵尸进程?](#2.1 什么是僵尸进程?)
- [2.2 为什么会有僵尸进程?](#2.2 为什么会有僵尸进程?)
- [2.3 僵尸进程的危害?](#2.3 僵尸进程的危害?)
- [2.4 如何产生一个僵尸进程?](#2.4 如何产生一个僵尸进程?)
- [2.5 如何清除僵尸进程?](#2.5 如何清除僵尸进程?)
- [2.6 如何避免僵尸进程?](#2.6 如何避免僵尸进程?)
进程状态 --- 僵尸进程
一、进程状态 --- Zombies
- Z (Zombies) :进程已经执行完毕并终止了,但其父进程还没有调用
wait()
或waitpid()
系统调用来回收它子进程退出状态信息。此时,这个已经死亡的进程就成为了 "僵尸进程"。 - 重要:僵尸进程已经不占用任何内存或CPU资源,它仅仅在进程表中保留一个入口,记录其退出状态,供父进程查询。如果父进程一直不回收,它就会一直存在 -(僵死进程会以终⽌状态保持在进程表中,并且会⼀直在等待父进程读取退出状态代码)
- 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入 Z(Zombies) 状态
二、僵尸进程
2.1 什么是僵尸进程?
故事插入:

如上所述,僵尸进程 是一个已经终止但尚未被其父进程回收的进程。
2.2 为什么会有僵尸进程?
这是Unix系统进程状态设计的一部分。设置僵尸状态是为了维护进程的退出信息,以便父进程能够查询子进程是如何死掉的(是正常退出还是被信号杀死?退出码是多少?)。
只有当父进程读取了这些信息后,内核才会彻底清除这个僵尸进程。


1.那些信息:进程退出时,必须要维持进程的基本相关信息(哪些基本信息?),让父进程得知其退出情况
2.信息存在哪里?当进程退出时,其退出信息是要保存在 task_struct
中(因为代码、数据已经被释放了,就只剩下 PCB
了),必须维持PCB(操作系统中的数据结构)。我们可以通过父进程的系统调用获取到子进程的特殊信息,我们就知道这个进程是因为什么原因而退出的。所以在子进程已经退出之后,父进程没有获取子进程的信息之前,这个子进程就是僵尸进程
2.3 僵尸进程的危害?
- 资源占用:僵尸进程本身不消耗内存和CPU。
- 主要危害 :每个僵尸进程都会在系统的进程表中占用一个槽位(即一个进程ID,PID)。如果系统中存在大量僵尸进程,进程表会被填满,导致系统无法创建新的进程,从而引发严重问题。
- 内存泄漏问题
2.4 如何产生一个僵尸进程?
一个典型的例子:父进程创建了子进程,但父进程忙于自己的工作,没有调用 wait()
来等待子进程结束。子进程先于父进程结束,就会变成僵尸。
简单C代码示例:
cpp
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main () {
pid_t child_pid = fork(); // 创建子进程
if (child_pid > 0) {
// 父进程
sleep(60); // 父进程睡眠60秒,而不调用 wait()
// 在这60秒内,子进程已经结束,会成为僵尸
} else {
// 子进程
exit(0); // 子进程立即退出
}
return 0;
}
编译运行上述程序,在父进程睡眠的60秒内,用 ps aux | grep Z
命令就可以看到状态为 Z+
的子进程。
验证 "Z" 状态

处于僵尸状态的进程的PCB需一直维护,而PCB
本就是一个进程的 task_struct
的对象,这会一直占用内存空间 ------ 引发内存泄漏问题!
所以,不是只有 new/malloc
会引起内存泄漏
,僵尸进程也会引起内存泄漏
------ 解决方法:通过 wait()_pid
的方式等待子进程并获取子进程退出结果
因此,父进程在未来除了获取子进程退出信息,还会进入等待模式将子进程的PCB释放掉 ------ 解决内存泄漏问题
2.5 如何清除僵尸进程?
- 正确方法 :让父进程调用
wait()
或waitpid()
来回收子进程。 - 常用方法 :如果父进程不回收,最直接的方法就是杀死父进程 。父进程被杀后,其所有子进程(包括僵尸进程)会变成"孤儿进程",被 init 进程(PID=1)收养。init 进程会定期调用
wait()
,从而清理这些僵尸进程。- 命令:
kill <父进程的PID>
- 命令:
- 警告 :不要试图用
kill -9
杀死僵尸进程本身,因为它已经是死掉的进程,信号无法作用在它身上。
2.6 如何避免僵尸进程?
- 在编写程序时,父进程应该使用
wait()
或waitpid()
系统调用来等待子进程结束。 - 或者,父进程可以捕获
SIGCHLD
信号(当子进程状态改变时,内核会向父进程发送此信号),并在信号处理函数中调用wait()
。
🌟 各位看官好 ,我是工藤新一¹呀~
🌈 愿各位心中所想,终有所致!