一、认识进程
1.1 进程是什么
| 项目 |
内容 |
| 基本定义 |
进程是操作系统中的一次执行过程 ,是资源分配和调度的基本单位。 程序(静态代码)加载到内存并分配资源执行的整套动态流程称为进程。 |
| 内核表示 |
用户执行程序时,内核空间 会创建一个 task_struct 结构体 来代表当前进程。 |
| 存储信息 |
进程运行产生的所有信息(状态、PID、内存指针等) 均保存在 task_struct 中。 |
| 正常结束 |
进程执行完毕,内核回收 task_struct。 |
| 异常崩溃 |
内核会清理资源,防止产生僵尸进程。 |
| 运行状态 |
等待CPU调度的进程称为就绪进程。 |
| 执行视角 |
微观 :单核CPU同一时刻只能运行一个进程。 宏观 :因轮转切换极快 ,看起来多个进程在同时运行。 |
| 隔离机制 |
宏观上通过隔离机制将用户空间 (数据)与内核空间 (如 task_struct)分离 以保证系统稳定性。 |
1.2 进程的核心特征
| 特征 |
含义 |
| 动态性 |
进程是程序的一次执行过程 ,动态产生、动态消亡。进程有完整的生命周期 创建-暂停-继续执行-回收(运行状态会动态改变) |
| 并发性 |
多个进程可以在一段时间内同时推进(并发执行)。 CPU不能被一个进程长时间霸占 ,否则会出现进程饥饿和系统奔溃 |
| 独立性 |
进程是资源分配和调度的基本单位 ,能独立运行。 |
| 异步性 |
进程以不可预知的速度独立前进 ,执行可能被中断,具有间断性。 |
二、程序与进程的关系
2.1 程序与进程的区别
| 对比维度 |
程序 (Program) |
进程 (Process) |
| 定义 |
静态的指令集合 ,存储在磁盘上的可执行文件(如 .exe);未执行时不占用系统资源 |
程序的动态执行过程 ,是程序运行时的实例,占用 CPU、内存、I/O 等系统资源,有生命周期 |
| 存在形式 |
静态存在, 以文件形式长期存储 |
动态存在 ,随程序启动而创建,随执行结束而销毁 |
| 资源占用 |
不占用 CPU、内存等运行时资源,仅占用磁盘存储空间 |
占用 CPU、内存、文件句柄、网络端口等系统资源,有独立的地址空间 |
| 状态 |
无状态(仅为指令和数据的静态集合) |
有状态(如运行态、停止态等) ,状态会随系统调度变化 |
| 独立性 |
多个程序之间相互独立,无直接关联(除非通过文件等外部方式交互) |
每个进程有独立的地址空间和资源 ,进程间默认不共享数据(需通过进程间通信机制实现) |
| 示例 |
硬盘上的 "浏览器.exe" 文件 |
双击 "浏览器.exe" 后运行的浏览器窗口 |
2.2 程序与进程的关联
| 项目 |
内容 |
| 进程与程序的对应关系 |
进程是程序的执行过程,一个程序可以对应多个进程(如同时打开多个浏览器窗口) |
| 角色定位 |
程序是进程的"模板 ",进程是程序的"运行态体现" |
| 行为逻辑 |
进程的执行过程本质是按程序指令逐步推进 ,程序的逻辑决定进程的行为 |
| 代码与数据共享 |
同一程序的多个进程共享程序的代码段 (只读),但各自拥有独立的数据段 |
| 关闭进程后 |
程序文件仍存在于磁盘 |
| 删除程序文件后 |
已运行的进程可继续执行(运行时相当于有程序的副本) 直到依赖该文件时才会出错 |
三、进程组成与运行属性
3.1 进程的组成
| 组成部分 |
说明 |
| 进程控制块 (PCB) |
操作系统用于管理和控制进程的核心数据结构,每个进程在内存中有唯一的PCB,记录进程识别信息、状态信息、内存管理信息、资源占用信息等,是操作系统感知进程存在的依据 |
| 文本段 |
存储可执行指令的内存区域(程序编译后的机器码);通常设置为只读 ,防止程序意外修改自身指令;多个运行同一程序的进程可共享同一份文本段,节省内存空间;大小在进程运行期间不会改变 |
| 数据段 |
存储进程运行过程中需要的数据;根据数据的"初始化状态"和"可修改性",分为:初始化数据段、未初始化数据段、堆、栈 |
3.2 虚拟地址与物理地址的映射关系
程序打印出的是虚拟地址,防止物理地址泄露
虚拟地址有可能重合,是抽象的
MMU通过虚拟地址和进程号 来访问物理地址,还会把磁盘的一部分空间当成内存使用
实际上物理地址只有你用到的地址并没有1G,如果超出了MMU会拓展内存 (有可能不连续,但虚拟地址一定连续)
3.3 Linux系统进程类型
| 进程类型 |
定义 |
特点 |
| 交互进程 |
由 shell 维护,需要用户在终端手动启动的进程,通过 shell 和用户进行交互(用户交互输入/输出) |
依赖终端环境,通常在前台运行,生命周期与用户操作相关 |
| 批处理进程 |
无需用户实时交互,优先级比较低,按预设任务序列自动运行的进程,通常在后台执行 |
优先级较低(避免占用关键资源),多通过脚本或任务调度工具启动 |
| 守护进程 |
系统启动时自动运行的后台进程,独立于终端,通常随系统启动而启动,随系统关闭而终止,用于提供持续服务 |
运行时脱离终端 |
3.4 进程的状态
| 状态名称 |
状态标识 |
说明 |
| 运行状态 |
R |
也称为可运行状态,表示进程正在CPU上执行或等待CPU调度运行。 |
| 可中断睡眠状态 |
S |
进程正在等待某个事件(如I/O操作、特定信号等)完成。该状态可以被信号或中断唤醒。 |
| 不可中断睡眠状态 |
D |
进程正在等待关键硬件操作完成,不能被信号中断,主要用于确保数据完整性。 |
| 停止状态 |
T |
进程被暂停执行,通常是由于收到了SIGSTOP等信号或被调试器暂停。可通过SIGCONT等信号恢复运行。 |
| 僵尸状态 |
Z |
进程已经终止,但其占用的部分资源(主要是PCB)尚未被回收,等待其父进程来读取退出状态信息。 |
| 死亡状态 |
X |
进程彻底终止,所有资源已被系统回收。这是一个瞬间状态,几乎无法通过工具观测到。 |
3.5 进程的附加状态
| 标记 |
含义 |
说明 |
+ |
前台进程组 |
进程属于前台进程组,与当前终端直接关联,用户可以通过终端输入直接控制。 |
l |
多线程进程 |
表示进程包含线程(LWP),通常对应多线程程序。 |
N |
低优先级进程 |
进程的nice值为正数(NI > 0),优先级较低,CPU资源会优先分配给其他进程。 |
< |
高优先级进程 |
进程的nice值为负数(NI < 0),优先级较高,会优先获取CPU资源。 |
s |
会话leader进程 |
表示进程是会话首进程,负责管理一个会话中的其他进程。 |
L |
进程持有锁 |
表示进程正在持有某个文件锁或资源锁,可能在等待其他进程释放锁资源。 |
进程状态图
3.6 进程PID
| 项目 |
说明 |
| 基本定义 |
PID是进程的唯一身份标识,操作系统为每个进程分配一个数字编号。 |
| 取值规则 |
PID是≥0的整数,实际分配从1开始(0号进程为特殊进程,如swapper或idle)。 |
| 数量限制 |
系统能创建的进程总数有限,可通过命令 sysctl kernel.pid_max 查看系统允许的PID上限。 |
| 查看机制 |
Linux通过 /proc 文件系统暴露进程信息。每个运行的进程对应 /proc/[PID] 目录(例如,PID为80320的进程对应 /proc/80320)。 |
| 详细信息 |
在进程目录内的 status 文件(即 /proc/[PID]/status)中,存储了进程的详细信息,包括PID、名称、运行状态等。 |
3.7 特殊PID
| 特殊PID |
进程名称 |
作用与职责 |
| 0号 |
idle |
系统启动后的第一个进程,负责空闲CPU调度(无其他进程运行时,idle进程占用CPU)。 |
| 1号 |
init |
由0号进程创建,负责初始化系统硬件、启动服务、回收孤儿进程(如关机时清理残留进程)。 |
| 2号 |
kthreadd |
负责内核进程调度(管理系统后台的内核级任务,如磁盘I/O、内存回收)。 |
四、进程的相关命令
4.1 ps命令
功能:用于查看当前系统中进程的快照信息,包括进程的PID(进程标识符)、所属用户、占用CPU和内存资源情况等;
| 常用具体命令 |
选项 |
功能 |
| ps -ef |
-e:列出系统中所有进程 -f:以全格式显示进程信息 |
查看当前所有进程 |
| ps -aux |
-a:显示所有终端进程 -u:以用户资源视角为中心的格式 -x:显示无终端进程(如后台服务) |
展示进程资源占用百分比(如CPU占用百分比、内存占用百分比等) |
| ps -eo 字段1,字段2... |
-e:列出系统中所有进程 -o:自定义输出格式 |
精准提取进程字段(如 pid, comm) |
| ps -l |
-l:长格式 |
以长格式查看当前终端进程详细信息 |
4.2 op命令
功能:动态的显示系统中各个进程的资源使用情况,可以实时查看进程的CPU使用率、内存使用量、线程数等,并且能按照不同的指标进行排序;
4.3 htop命令
功能:是一个交互式的进程查看工具,相比top具有更友好的用户界面,支持鼠标操作;可以更加直观地展示进程树结构;
4.4 kill命令
功能:用于向进程发送信号,最常见的就是用来终止进程。通过指定进程的PID,发送特定的信号让进程执行相应的操作,比如终止、暂停等等;
| 命令格式 | 信号编号 | 对应信号名称 | 功能说明 |
| kill -l | - | - | 列出系统中所有可用的信号及其编号 |
| kill -2 pid | 2 | SIGINT | 向指定进程发送中断信号(通常由键盘 Ctrl+C 触发,进程可捕获并处理该信号) |
| kill -9 pid | 9 | SIGKILL | 强制终止指定进程(进程无法捕获或忽略该信号,将立即终止) |
| kill -19 pid | 19 | SIGSTOP | 暂停指定进程的运行(进程无法捕获或忽略该信号,将立即停止) |
| kill -18 pid |
18 |
SIGCONT |
使已暂停的进程恢复运行(通常与 SIGSTOP 或 SIGTSTP 配合使用) |
4.5 killall命令
功能:根据进程名来终止进程,当系统中有多个同名进程需要同时终止时,killall就非常方便;
| 命令格式 |
信号编号 |
对应信号名称 |
功能说明 |
| killall 进程名 |
- |
- |
终止所有名为"进程名"的进程(默认发送 SIGTERM 信号) |
| killall -9 进程名 |
9 |
SIGKILL |
强制终止所有同名进程 |
| killall -i 进程名 |
- |
- |
终止前逐一询问确认(交互模式) |
4.6 pstree命令
功能:以树结构显示进程之间的父子关系,从系统初始化init开始,直观地展示整个系统进程的层次结构;
4.7 bg/fg命令
| 命令格式 |
功能说明 |
注意事项 |
| bg 作业号 |
将挂起的进程放到后台,继续运行 |
若不指定作业号,默认操作最近一个被挂起的作业;作业号可通过 jobs -l 命令查看获取 |
| fg 作业号 |
把后台运行的进程,放到前台终端运行,恢复与终端交互 |
若不指定作业号,默认将最近一个后台作业调至前台;调至前台后,进程会占据终端输入输出,直到进程结束或再次被暂停 |
4.8 nice/renice命令
| 命令 |
功能 |
命令格式 |
| nice |
启动进程时设置优先级(未指定值时默认优先级增量为10) |
nice -n 优先级值 要执行的命令 |
| renice |
调整已运行进程的优先级,可针对单进程、用户所有进程进行调整 |
renice 新优先级值 -p 进程PID(调整单个进程) renice 新优先级值 -u 用户名(调整用户的所有进程) |
五、进程的创建
5.1 fork函数
| 项目 |
内容 |
| 所需头文件 |
#include <sys/types.h> #include <unistd.h> |
| 函数原型 |
pid_t fork(void); |
| 功能 |
复制当前进程,创建子进程 |
| 参数 |
无 |
| 成功(父进程) |
返回大于0的整数(子进程的PID) |
| 成功(子进程) |
返回0 |
| 失败 |
子进程未被创建,父进程收到 -1,并设置错误码 |
5.2 父子进程内存空间
父进程在fork产生子进程时,用到了写时拷贝的原则;
如果父子进程中对内存进行读操作,那么内存不会被重新映射物理内存;
如果父子进程中的任意一方对内存有写操作时,才会重新映射到新的物理内存;