进程是操作系统中正在运行的程序实例,它具有多种状态,这些状态反映了进程在生命周期中的不同阶段以及当前的执行情况。
一、就绪状态(Ready)
- 定义:进程已具备执行所需的所有条件,只等待操作系统分配CPU资源即可执行。
- 特点:
- 进程的程序、数据及相关资源已加载到内存中。
- 处于就绪队列中,等待调度器选择执行。
- 一旦获得CPU时间片,可立即转入运行状态。
- 示例:多个应用程序在后台打开时,未被当前CPU执行的程序即处于就绪状态。
二、运行状态(Running)
- 定义:进程正在CPU上执行。
- 特点:
- 进程占用CPU资源,执行指令序列。
- 同一时刻,单CPU系统中只有一个进程处于运行状态(多CPU系统可同时有多个)。
- 进程可能因时间片用完、等待I/O操作或被更高优先级进程抢占而退出运行状态。
- 示例:当前正在前台运行的浏览器或文档编辑软件。
- R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
三、阻塞状态(Blocked/Waiting)
- 定义:进程因等待某一事件(如I/O操作完成、资源获取、信号等)而暂时无法执行,处于暂停状态。
- 特点:
- 进程不占用CPU资源,主动放弃CPU。
- 等待的事件发生前,无法转换为运行状态。
- 事件完成后(如磁盘读取数据完成),进程转入就绪状态,等待再次调度。
- 示例:下载文件时,进程因等待数据从磁盘读取到内存而进入阻塞状态。
四、创建状态(New)
- 定义:进程正在被创建的过程中,系统为其分配资源、初始化数据结构。
- 特点:
- 尚未完全建立进程控制块(PCB)和资源分配。
- 处于从无到有的过渡阶段,完成后转入就绪状态。
- 示例:双击打开一个应用程序时,系统创建进程的初始阶段。
五、终止状态(Terminated/Exit)
- 定义:进程已执行完毕或因错误、中断等原因终止,正在释放资源。
- 特点:
- 进程的所有任务已完成,或被操作系统强制终止。
- 系统回收其占用的内存、文件句柄等资源。
- 最终从系统中移除,状态消失。
- 示例:正常关闭程序或程序崩溃时,进程进入终止状态。
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
六、挂起状态(Suspended)
- 定义:进程被暂时调出内存,存储到外存(如硬盘)中,以释放内存资源。
- 特点:
- 分为“就绪挂起”和“阻塞挂起”两种子状态:
- 就绪挂起:进程在外存中等待调入内存并获取CPU。
- 阻塞挂起:进程在外存中等待事件发生,事件完成后先调入内存再转就绪。
- 挂起状态可减少内存占用,适用于多任务低内存场景。
- 示例:系统内存不足时,后台长时间未使用的进程可能被挂起。
S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
七、僵尸进程(Zombie Process)
- 定义与本质
概念:僵尸进程是指进程已终止(执行完毕或被终止),但尚未被其父进程回收资源的状态。
本质:进程控制块(PCB)仍保留在系统中,占用 PID(进程标识符)等资源,但实际代码段和数据段已释放。
- 产生原因
父进程未调用回收函数:进程终止时,会向父进程发送SIGCHLD信号,若父进程未通过wait()或waitpid()函数回收子进程资源,子进程就会变为僵尸进程。
父进程异常:父进程提前终止或进入死循环,无法处理子进程的终止信号。
- 特点与影响
状态特征:
在系统中显示为Z或zombie状态(通过ps -ef或top命令查看)。
不占用 CPU 和内存等运行资源,但占用 PID 资源(PID 数量有限,过多僵尸进程会导致新进程无法创建)。
负面影响:
PID 资源耗尽:Linux 系统中 PID 范围通常为 1~32768,僵尸进程长期存在会占用 PID,导致新进程无法创建。
系统性能下降:内核需持续维护僵尸进程的 PCB,增加调度开销。
总结
僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程,没有读取到子进程退出的返回代码时就会产生僵死(尸)进程僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
八、孤儿进程
孤儿进程(Orphan Process)是操作系统中的一种特殊进程状态,通常出现在父进程先于子进程结束时。
- 定义
孤儿进程是指其父进程已经终止,但子进程仍然在运行的进程。由于父进程已经不存在,子进程失去了“监护”,因此被称为孤儿进程。
子进程的父进程会改为1号进程也就是操作系统
- 产生原因
父进程先于子进程结束:在多进程程序中,父进程可能会因为正常结束、被强制终止(如通过kill命令)或其他原因退出。如果此时子进程仍在运行,则子进程会变成孤儿进程。
子进程尚未完成任务:子进程可能还在执行某些任务(如I/O操作、计算等),而父进程已经完成其工作并退出。
- 特点
失去父进程:孤儿进程的父进程已经不存在,因此它无法再从父进程那里获取资源或信号。
被系统接管:在大多数操作系统中,孤儿进程会被系统接管,通常由一个特殊的进程(如init进程或systemd进程)成为其新的父进程。这个接管进程会负责清理孤儿进程的资源。
无法被终止:孤儿进程不会自动终止,它会继续运行,直到完成其任务或被系统接管后清理。
- 处理方式
被init进程接管(在类Unix系统中):
在类Unix系统(如Linux)中,当一个进程成为孤儿进程时,它会被init进程(进程ID为1)接管。init进程是一个特殊的进程,负责管理所有孤儿进程。
init进程会等待孤儿进程结束,并清理其资源(如回收进程表条目、释放内存等)。
被systemd进程接管(在现代Linux系统中):
在现代Linux系统中,systemd进程取代了传统的init进程,成为系统的初始化进程。孤儿进程同样会被systemd进程接管,并由其负责清理资源。
- 孤儿进程与僵尸进程的区别
孤儿进程:
父进程已经终止,但子进程仍在运行。
孤儿进程会被系统接管(如init或systemd),并继续运行直到完成任务。
僵尸进程:
子进程已经终止,但父进程尚未读取其状态信息。
僵尸进程无法被终止,只能等待父进程读取其状态信息后才能被清理。
僵尸进程不会占用CPU资源,但会占用进程表中的一个条目。
虽然孤儿进程本身不会对系统造成严重问题(因为它们会被系统接管),但在某些情况下,开发者可能希望避免产生孤儿进程。以下是一些方法:
- 确保父进程等待子进程完成:父进程可以通过调用wait()或waitpid()函数来等待子进程结束,从而避免子进程成为孤儿进程。
- 使用信号处理:父进程可以设置信号处理函数,捕获终止信号(如SIGTERM或SIGINT),并在退出前清理子进程。
- 合理设计程序逻辑:在设计多进程程序时,确保父进程和子进程的生命周期合理匹配,避免父进程过早退出。
进程状态转换图
+---------+
| 运行 |
+----+----+
|
▼
+------------+------------+
| |
+--------▼------------▼------------▼--------+
| |
+---------+ +---------+ |
| 就绪 | | 阻塞 | |
+----+----+ +----+----+ |
| | |
| +------------+ | |
| | 挂起/唤醒 | | |
▼ +------+-----+ ▼ ▼
+---------+ +---------+ +---------+ +---------+
|就绪挂起 | |阻塞挂起 | | 创建 | | 终止 |
+---------+ +---------+ +----+----+ +----+----+
状态转换的触发条件
- 就绪→运行:调度器分配CPU时间片。
- 运行→就绪:时间片用完、被更高优先级进程抢占。
- 运行→阻塞:等待I/O操作、资源锁或用户输入。
- 阻塞→就绪:等待的事件完成(如I/O操作结束)。
- 运行/就绪/阻塞→终止:进程执行完毕、出错或被强制关闭。
- 就绪/阻塞→挂起:系统内存不足,进程被调出到外存。
- 挂起→就绪/阻塞:进程被重新调入内存,等待事件或CPU。
总结
进程状态是操作系统管理资源和调度任务的核心机制,通过状态转换实现多任务并发执行和资源高效利用。理解这些状态有助于分析程序性能问题(如阻塞导致的卡顿)、优化系统调度策略,以及掌握操作系统的底层工作原理。