【Linux系统】进程状态 | 进程优先级
I. 进程状态进程状态的概念介绍进程状态是操作系统用来描述进程在生命周期中不同活动阶段的核心概念。进程在执行过程中会因资源请求、事件等待或调度策略而改变状态这些状态反映了进程的当前行为如运行、等待或终止。状态转换由操作系统内核管理确保系统资源高效分配。例如一个进程可能从“运行”状态切换到“阻塞”状态以等待用户输入事件完成后又回到“运行”状态。理解进程状态有助于分析系统性能如CPU利用率或响应延迟。举例帮助理解 想象一个简单的文本编辑器进程当用户输入文字时进程处于运行状态CPU执行编辑操作。如果用户暂停输入进程进入阻塞状态等待键盘事件。若系统内存不足操作系统可能将进程换出到磁盘进入挂起状态释放内存但保留进程数据。用户关闭编辑器时进程终止并短暂成为僵尸状态等待父进程回收资源最终变为死亡状态。这个例子展示了状态如何随事件用户操作、资源变化动态转换体现了操作系统的调度机制。1. Linux进程状态的内核定义1.内核源码中的状态定义Linux内核源代码如task_state_array明确定义了进程状态这些状态存储在进程控制块PCB的字段中用宏表示不同数值。以下是关键状态及其含义R (running): 进程正在CPU执行或在运行队列中等待调度。注意它不一定是当前运行中而是“可运行”状态。示例CPU密集型循环如while(1);的进程状态为R而含printf的循环因等待显示器就绪变为S。S (sleeping): 可中断睡眠状态进程等待事件如I/O完成或信号可被外部信号唤醒。例如scanf等待输入。D (disk sleep): 不可中断睡眠状态进程等待硬件操作如磁盘I/O不能被信号中断。若强行终止可能导致数据损坏。例如数据库进程写入磁盘时进入此状态。T (stopped): 暂停状态进程被信号如SIGSTOP强制停止可通过SIGCONT恢复。调试程序时常见此状态。Z (zombie): 僵尸状态进程已终止但PCB未被父进程回收占用少量内存资源。例如父进程未调用wait()时子进程残留为僵尸。X (dead): 死亡状态进程完全终止且资源已释放不会出现在任务列表中。源代码片段参考代码语言javascriptAI代码解释static const char *const task_state_array[] { R (running), /*0 */ // 运行或就绪 S (sleeping), /*1 */ // 可中断睡眠 D (disk sleep), /*2 */ // 不可中断睡眠 T (stopped), /*4 */ // 停止 t (tracing stop), /*8 */ // 跟踪停止调试 X (dead), /*16 */ // 死亡 Z (zombie), /*32 */ // 僵尸 };此定义体现了Linux状态设计的“位图”特性如状态值可组合便于内核进行高效位测试。2.状态转换触发条件转换路径触发场景R → S进程执行阻塞操作如sleep()、read()等待I/O16S → R等待的资源就绪如I/O完成或被信号唤醒6R → D发起不可中断的系统调用如同步磁盘写入3R → T收到SIGSTOP或CtrlZT → R收到SIGCONT信号1R → Z子进程exit()后父进程未回收7案例解释 若vim编辑文件时磁盘故障进程进入D状态。此时kill无效需重启或修复硬件3。而后台下载工具因网络中断进入S状态网络恢复后自动唤醒。2. 运行、阻塞、挂起进程状态的本质剖析运行状态Running概念进程正在CPU执行或位于运行队列中准备执行。在Linux中对应R状态强调“可调度性”而非实际占用CPU。细节运行队列run_queue存储所有可运行进程的PCB调度器从中选择进程分配CPU时间片。若进程被更高优先级进程抢占会返回运行队列等待。示例多任务系统中浏览器和音乐播放器进程交替进入运行状态共享CPU资源。阻塞状态Blocked概念进程因等待资源如I/O、信号而暂停执行分为两类可中断阻塞S状态可被信号唤醒如SIGKILL。例如网络下载进程等待数据包时休眠收到取消信号后立即退出。不可中断阻塞D状态仅由特定事件如硬件操作完成唤醒避免数据不一致。例如文件系统进程写入磁盘时不可中断。与运行状态关系阻塞是运行的反面——进程因资源短缺退出运行队列加入等待队列。挂起状态Suspended概念进程被操作系统移出内存换到磁盘Swap分区释放物理内存资源。挂起常与阻塞关联挂起必阻塞但阻塞未必挂起。细节Linux未直接定义挂起状态但通过机制如交换空间实现当内存不足时内核将阻塞进程挂起。唤醒时进程需从磁盘加载回内存再进入就绪队列。示例大型编译任务在后台运行时若系统内存紧张可能被挂起用户切回时重新加载继续执行。双重状态阻塞且挂起进程数据在磁盘等待资源就绪但挂起进程数据在磁盘可运行但需先换入内存风险提示频繁挂起预示内存枯竭可能触发OOM Killer强制杀进程。状态转换示例 一个视频编码进程运行编码时占用CPUR状态。阻塞读取大文件时等待磁盘I/O进入S或D状态。挂起若系统负载高进程被换出到磁盘隐含阻塞。唤醒磁盘操作完成进程加载回内存返回运行队列R状态。 此过程展示了资源竞争如何驱动状态转换。3. PCB存储结构与组织方式PCBtask_struct的核心作用PCB是Linux内核中task_struct结构体存储进程所有元数据如状态、优先级、内存映射。它是进程的唯一标识通过链表和队列实现状态管理代码语言javascriptAI代码解释struct task_struct { volatile long state; // 进程状态0R,1S,... struct mm_struct *mm; // 内存管理结构含代码/数据地址 pid_t pid; // 进程ID struct files_struct *files; // 打开文件表 // 以上我们现在先不用去关心 // 这次介绍的重点 struct list_head struct list_head tasks; // 链表节点用于组织队列 // ...优先级、调度策略、寄存器值等 };存储结构状态字段state变量存储当前状态值如TASK_RUNNING宏对应R状态。队列指针PCB包含next和prev指针链接到运行队列或阻塞队列。其他成员包括调度信息优先级、资源句柄打开文件、父子进程指针等。我们来看看struct list_head代码语言javascriptAI代码解释struct list_head { struct list_head *next, *prev; };这个极简结构只有两个指针next指向下一个节点prev指向前一个节点设计哲学侵入式链表- 链表节点嵌入宿主结构体而非包裹数据I. 宿主结构体获取代码语言javascriptAI代码解释// Linux2.0内核版本 #define container_of(ptr, type, member) \ ((type *)((char *)(ptr) - (unsigned long)(((type *)0)-member)))container_of宏是Linux内核中最重要的基础宏之一它实现了通过结构体成员地址获取整个结构体地址的神奇功能。让我们逐层解剖这个精妙的设计。一、宏参数说明参数类型作用ptr指针指向结构体成员的指针type数据类型目标结构体的类型member成员名结构体中该成员的名称二、工作原理详解步骤1计算成员偏移量offsetof代码语言javascriptAI代码解释((type *)0)-member操作分解(type *)0将0地址强制转换为指向type类型的指针效果假设地址0处存在一个type类型的结构体实例-member访问该虚拟结构体的成员关键此时成员member的地址就是其相对于结构体起始位置的偏移量取该成员的地址结果得到成员member在结构体中的偏移字节数示例计算task_struct中tasks成员的偏移代码语言javascriptAI代码解释struct task_struct { // ... struct list_head tasks; // ... }; size_t offset (unsigned long)((struct task_struct *)0)-tasks;步骤2类型转换与指针运算代码语言javascriptAI代码解释(char *)(ptr) - (unsigned long)(/*偏移量*/)操作分解(char *)(ptr)将成员指针转换为char*类型目的进行字节级指针运算char类型保证按字节计算- (unsigned long)(/*偏移量*/)从成员地址减去偏移量结果得到包含该成员的结构体起始地址步骤3类型转换回目标结构体代码语言javascriptAI代码解释((type *) /* 计算出的地址 */)将计算出的地址转换回type*类型得到指向完整结构体的指针三、完整计算过程图示代码语言javascriptAI代码解释内存布局示意图 结构体起始地址 --------------------- ---- struct task_struct * | 其他成员 | | | --------------------- ---- ((struct task_struct*)0)-tasks | struct list_head | \ | tasks | | 偏移量 此地址 - 0 | (next, prev) | / --------------------- | 其他成员 | | | ---------------------计算过程已知tasks成员的地址ptr 0x1008计算偏移量offset 0x200假设值结构体起始地址 ptr - offset 0x1008 - 0x200 0x0E08II. 在内核中的实际应用1. 进程管理代码语言javascriptAI代码解释// kernel/sched/core.c struct task_struct { struct list_head tasks; // 全局进程链表 struct list_head children; // 子进程链表 struct list_head sibling; // 兄弟进程链表 // ... };2. 页面管理代码语言javascriptAI代码解释// mm_types.h struct page { struct list_head lru; // 页面缓存链表 // ... };3. 文件系统代码语言javascriptAI代码解释// fs.h struct super_block { struct list_head s_list; // 超级块链表 // ... }; struct inode { struct list_head i_sb_list; // 超级块中的inode链表 // ... };4. Z(zombie)-僵尸进程一、僵尸状态的定义本质 进程完成执行后其代码和数据占用的内存资源会被系统释放但进程控制块PCB仍被保留在操作系统的进程表中等待父进程查询其退出状态如退出码、资源使用统计等。此时进程不再消耗CPU或内存资源仅占用一个进程IDPID和进程表项。在系统状态查看工具如ps中此类进程标记为Z或Zombie。触发条件 子进程终止 → 父进程仍在运行 → 父进程未主动获取子进程退出信息 → 子进程进入僵尸状态。关键点僵尸状态是父子进程协同机制的结果而非子进程自身行为错误。二、为什么需要僵尸状态僵尸状态的存在是操作系统的设计必然原因如下保存退出信息 子进程退出时需向父进程传递终止原因如正常退出码、被信号杀死等。若父进程未及时读取系统需临时保存这些信息。类比示例快递员子进程将包裹退出状态送达收件人父进程后需等待签收确认。若收件人未签收包裹需暂存仓库进程表快递员状态即为“待确认”Zombie。父进程的知情权 父进程可能依赖子进程的退出状态决策后续操作例如Shell中通过$?获取上一条命令的退出码服务监控程序需判断子进程是否异常崩溃。 若系统直接回收子进程这些信息将丢失。资源释放的中间态 进程终止需分两步释放内存与文件资源子进程退出时完成释放PCB资源父进程读取状态后由系统回收。 僵尸状态即第二步未完成时的“半释放”状态。三、生动示例模拟僵尸进程假设编写以下C程序代码语言javascriptAI代码解释#include stdio.h #include sys/types.h #include unistd.h int main() { pid_t id fork(); if(id 0) { //child int count 5; while(count) { printf(我是子进程我正在运行: %d\n, count); sleep(1); count--; } } else { // father while(1) { printf(我是父进程我正在运行...\n); sleep(1); } } return 0; }然后我们使用ps指令来检测一下每隔一秒检测一次代码语言javascriptAI代码解释while :; do ps axj | head -1 ps axj | grep myprocess | grep -v grep; sleep 1; echo ###### ; done指令结构拆解代码语言javascriptAI代码解释while :; do ps axj | head -1 ps axj | grep myprocess | grep -v grep; sleep 1; echo ######; done1.while :; do ... done无限循环:是 Bash 中的空命令永远返回真值因此while :表示永久循环。作用持续执行do和done之间的命令直到手动终止如CtrlC。2.ps axj | head -1显示进程表头ps axj列出系统中所有进程的详细信息a显示所有用户进程x包含无终端的进程j以作业格式输出。| head -1管道截取第一行即列标题PPID, PID, PGID, STAT等。作用每次循环先输出表头明确后续数据的含义。3.ps axj | grep myprocess | grep -v grep过滤目标进程ps axj | grep myprocess搜索进程列表中包含myprocess的行。| grep -v grep排除grep命令自身因grep运行时也会匹配myprocess。作用精准显示myprocess进程的状态信息如PID,STAT等。4.sleep 1控制刷新频率暂停 1 秒使循环每秒执行一次。作用避免高频刷新消耗资源平衡实时性与性能。5.echo ######输出分隔符打印######作为视觉分隔线。作用区分每次循环的输出块提升可读性。运行结果运行结果分析子进程终止 子进程循环5次后退出return 0释放内存和文件资源但PCB进程控制块保留。关键机制父进程未调用wait()/waitpid()回收退出状态子进程进入僵尸状态Z。父进程行为 继续无限循环完全未感知子进程终止持续打印运行信息。特征子进程STATZ僵尸。命令列显示[myprocess] defunctdefunct表示已终止。PPID仍为父进程PID605109表明父进程存活但未履行回收责任。僵尸进程持久化 只要父进程不终止或主动回收子进程的僵尸状态会一直存在占用PID和进程表项。危害若系统中僵尸进程过多进程表资源耗尽→ 新进程无法创建。四、僵尸进程的影响短期无害长期需警惕僵尸进程本身不消耗CPU/内存仅占用少量内核资源如PID。但若父进程长期不回收子进程僵尸进程累积将耗尽进程表导致系统无法创建新进程。典型场景服务器程序频繁创建子进程但未正确处理退出状态。5. 孤儿进程一、孤儿进程的本质想象一个场景父母突然消失孩子被社会福利机构接管。在Linux系统中孤儿进程父进程提前终止仍在运行的子进程领养机制内核将孤儿进程的父进程设置为init(PID1)或systemd回收保障由领养进程负责子进程退出后的资源回收关键点孤儿进程是运行中的活进程不是僵尸进程二、验证孤儿进程代码语言javascriptAI代码解释#include stdio.h #include sys/types.h #include unistd.h int main() { pid_t id fork(); if(id 0) { // child while(1) { printf(我是一个子进程 pid: %d, ppid: %d\n, getpid(), getppid()); sleep(1); } } else { // father int cnt 5; while(cnt) { printf(我是一个父进程 pid: %d, ppid: %d\n, getpid(), getppid()); cnt--; sleep(1); } } return 0; }还是使用刚才的ps指令进行查看运行结果0-5秒父子进程并发运行输出各自PID和PPID。子进程PPID为父进程PID如609390。5秒后父进程退出子进程PPID变为1init。后续子进程无限运行PPID始终为1。注意子进程从S变为S说明子进程从前台进程变为后台进程CTRL C只能杀掉前台进程后台进程是杀不掉的至于原因需要在后面讲解了信号才能理解但是这里可以使用kill -9 [pid]来进行终止三、孤儿进程与僵尸进程的对比及实际影响为全面理解对比两种进程的差异和实际影响(1)核心区别特性孤儿进程僵尸进程定义父进程先退出子进程仍在运行子进程终止父进程未回收进程状态运行中R/S终止Z父进程init/systemdPID1原父进程仍存活资源占用正常消耗CPU/内存仅占用PCB无CPU/内存消耗回收机制init自动回收需父进程手动wait或杀死父进程危害无累积导致进程表溢出(2)实际影响孤儿进程无害因init及时回收无资源泄漏风险系统设计已完美处理此场景。僵尸进程需警惕若父进程不调用wait()僵尸进程累积可能使系统无法创建新进程需kill -9 父进程强制回收。性能开销init的监控和回收操作由内核高效处理对系统性能影响可忽略。最佳实践在开发中父进程应通过waitpid(pid, status, WNOHANG)非阻塞回收子进程避免孤儿进程产生尽管无害。若需父进程提前退出无需额外处理依赖init机制即可。

相关新闻

LLM做文本分类,提示词加了很多示例,评估该用think模式还是非think模式

LLM做文本分类,提示词加了很多示例,评估该用think模式还是非think模式

LLM选用Qwen3-32B, 准备了一个人工标注的测试集,评估发现用think模式正确率较高, think模式正确率139/250, 非think模式正确率121/250, 非think模式LLM会忽略不少给的示例数据,比如我一共要分3个类ABC&…

2026/5/17 10:29:27 阅读更多 →
Linux 之从硬件硬盘到文件系统的全面过渡

Linux 之从硬件硬盘到文件系统的全面过渡

1. 理解硬件磁盘-服务器-机柜-机房机械磁盘是计算机中唯一的一个机械设备磁盘--- 外设慢容量大,价格便宜磁盘物理结构磁盘存储结构磁道是同心圆扇区:是磁盘存储数据的基本单位,512字节,块设备三片六面,六个磁头&#x…

2026/7/7 18:34:08 阅读更多 →
SpringSecurity踢出指定用户

SpringSecurity踢出指定用户

SpringSecurity中可以使用 SessionRegistry 的实现类 SessionRegistryImpl 来获取session相关信息,可以通过这个实现类来踢出用户。 SpringSecurity配置 EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {AutowiredISysUserSe…

2026/5/17 10:29:26 阅读更多 →

最新新闻

如何彻底解决网盘下载限速问题:9大平台直链解析工具完全指南

如何彻底解决网盘下载限速问题:9大平台直链解析工具完全指南

如何彻底解决网盘下载限速问题:9大平台直链解析工具完全指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 …

2026/7/8 7:59:29 阅读更多 →
9大主流网盘直链解析工具:告别限速困扰的高效下载解决方案

9大主流网盘直链解析工具:告别限速困扰的高效下载解决方案

9大主流网盘直链解析工具:告别限速困扰的高效下载解决方案 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / …

2026/7/8 7:57:29 阅读更多 →
D3KeyHelper:5分钟打造你的暗黑3专属鼠标宏,彻底告别手酸烦恼

D3KeyHelper:5分钟打造你的暗黑3专属鼠标宏,彻底告别手酸烦恼

D3KeyHelper:5分钟打造你的暗黑3专属鼠标宏,彻底告别手酸烦恼 【免费下载链接】D3keyHelper D3KeyHelper是一个有图形界面,可自定义配置的暗黑3鼠标宏工具。 项目地址: https://gitcode.com/gh_mirrors/d3/D3keyHelper 还在为暗黑破坏…

2026/7/8 7:57:29 阅读更多 →
.NET 项目集成可观测性:从架构思考到落地实践

.NET 项目集成可观测性:从架构思考到落地实践

本文基于一个真实的.NET 9项目集成可观测性栈的经历,分享从"为什么做"到"怎么落地"的完整过程。一、为什么需要集成可观测性? 1.1 触发点:一个"慢"接口 项目中有一个业务接口,涉及多表关联、缓存查…

2026/7/8 7:51:28 阅读更多 →
终极AI换脸指南:如何用roop-unleashed实现电影级面部替换效果

终极AI换脸指南:如何用roop-unleashed实现电影级面部替换效果

终极AI换脸指南:如何用roop-unleashed实现电影级面部替换效果 【免费下载链接】roop-unleashed Evolved Fork of roop with Web Server and lots of additions 项目地址: https://gitcode.com/gh_mirrors/ro/roop-unleashed 在数字创意领域,AI换脸…

2026/7/8 7:49:27 阅读更多 →
腾讯混元Hy3技术拆解:295B MoE架构、定价策略与Benchmark实测对比

腾讯混元Hy3技术拆解:295B MoE架构、定价策略与Benchmark实测对比

核心结论 腾讯于2026年7月6日正式发布混元Hy3,这是一个总参数295B、激活参数21B的MoE架构模型(192专家、每次激活Top-8),支持256K上下文窗口。本文从架构设计、定价策略、Benchmark实测三个维度进行技术拆解,并与GPT-5…

2026/7/8 7:49:27 阅读更多 →

日新闻

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破

3大核心能力重塑《明日方舟》游戏体验:MAA自动化助手的革命性突破 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: …

2026/7/8 0:00:48 阅读更多 →
MyBatis 批量操作深度优化——从 N+1 到批处理的全路径

MyBatis 批量操作深度优化——从 N+1 到批处理的全路径

MyBatis 批量操作深度优化——从 N1 到批处理的全路径 一、从"功能正确"到"性能可接受"——MyBatis 批量操作的三段式进化 MyBatis 在日常增删改查场景中几乎是无感的——实体映射直观、SQL 控制灵活。但当数据量从千级上升到十万级、百万级,许…

2026/7/8 0:00:48 阅读更多 →
工业负载控制方案:TPD2015FN与PIC18F45K22应用解析

工业负载控制方案:TPD2015FN与PIC18F45K22应用解析

1. 工业负载控制方案概述在工业自动化、电机驱动和照明控制等高需求场景中,可靠地控制电感和电阻负载是核心挑战之一。TPD2015FN作为东芝的8通道高端智能功率开关IC,配合PIC18F45K22微控制器,能够构建一套稳定、高效的负载控制系统。这套组合…

2026/7/8 0:02:48 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/7 14:24:45 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/7 12:34:47 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/7 15:59:06 阅读更多 →

月新闻