当前位置: 首页 > news >正文

Linux 进程状态 — 僵尸进程

在这里插入图片描述


在这里插入图片描述


🎁个人主页:工藤新一¹

🔍系列专栏:C++面向对象(类和对象篇)

🌟心中的天空之城,终会照亮我前方的路

🎉欢迎大家点赞👍评论📝收藏⭐文章


文章目录

  • 进程状态 — 僵尸进程
    • 一、进程状态 — Zombies
    • 二、僵尸进程
      • 2.1 什么是僵尸进程?
      • 2.2 为什么会有僵尸进程?
      • 2.3 僵尸进程的危害?
      • 2.4 如何产生一个僵尸进程?
      • 2.5 如何清除僵尸进程?
      • 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代码示例:

#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()

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

🌈 愿各位心中所想,终有所致!
在这里插入图片描述

http://www.xdnf.cn/news/1417429.html

相关文章:

  • FDTD_梯度波导学习(1)
  • HOW - 前端团队产出评定方案参考
  • 携程旅行 web 验证码 分析
  • JavaEE 进阶第一期:开启前端入门之旅(上)
  • GitLab 18.3 正式发布,更新多项 DevOps、CI/CD 功能【二】
  • 餐饮门店的小程序怎么做?如何开发餐饮店下单小程序?
  • C++11模板优化大揭秘:让你的代码更简洁、更安全、更高效
  • CICD实战(2) - 使用Arbess+GitLab+SonarQube实现Java项目快速扫描/构建/部署
  • 简单实现Ai音乐suno-api
  • TCP粘包
  • 考研复习-计算机网络-第一章-计算机网络概述
  • keil MDK如何使用第三方软件Keil2Json.exe生成compile_commands.json文件,方便vscode+clangd环境使用
  • 深度解析条件编译:#ifdef与#ifndef的本质区别与应用实践
  • [Android] 京墨 v1.15.2 —— 古诗词文、汉语字典、黄历等查询阅读学习宝典(可离线)
  • MTK-Android13-实现拷贝预置资源到vendor分区下
  • Scikit-learn Python机器学习 - 字典特征提取-DictVectorizer
  • 电脑没加域却能获取到IP地址
  • 基于单片机宠物项圈/宠物防丢失设计
  • 关于命名参数占位符的分析(主要以PHP为例)
  • 设计支持多代WiFi协议的DCF信道访问控制Verilog模块:技术挑战与实现策略
  • Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
  • c# winform 拼图游戏
  • 预处理——嵌入式学习笔记
  • leetcode 1576 替换所有的问号
  • Linux 定时任务 crontab 完全指南 —— 让服务器自动干活,解放双手
  • Kubernetes集群升级与etcd备份恢复指南
  • 《IC验证必看|随机稳定性 / 再现性》
  • 今日分享:C++ -- vector
  • Python备份实战专栏第4/6篇:Vue.js + Flask 打造企业级备份监控面板
  • line-height属性详解