Linux 进程状态 — 僵尸进程



🎁个人主页: 工藤新一¹

🔍系列专栏: 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()

🌟 各位看官好我是工藤新一¹呀~

🌈 愿各位心中所想,终有所致!

相关推荐
牛奶咖啡1335 分钟前
Linux中实现可执行文件或脚本在全局可用
linux·设置可执行程序全局可用·设置脚本全局可用·linux默认执行目录·linux环境变量
情深不寿3171 小时前
传输层————TCP
linux·网络·c++·tcp/ip
christine-rr1 小时前
【25软考网工】第五章(10) Internet应用
linux·网络·经验分享·笔记·软考
Arenaschi4 小时前
Android
android·linux·运维·笔记·其他·docker
敲上瘾4 小时前
Docker多容器编排:Compose 实战教程
linux·运维·docker·容器·架构
斯普信专业组9 小时前
LVS详解:构建高性能Linux负载均衡集群
linux·负载均衡·lvs
Sadsvit10 小时前
HAProxy 完整指南:简介、负载均衡原理与安装配置
linux·运维·服务器·负载均衡
silence25010 小时前
CentOS 下使用 LVM 扩展根分区空间的完整流程
linux·运维·centos
郝学胜-神的一滴10 小时前
基于Linux,看清C++的动态库和静态库
linux·服务器·开发语言·c++·程序人生
toooooop810 小时前
linux centos 脚本批量启动宝塔服务(二)
linux·运维·centos