作者:逆境不可逃
技术永无止境
希望我的内容可以帮助到你!!!!
大家吼 ! 我是 逆境不可逃 今天给大家带来文章
《操作系统核心知识体系 ------ 期末复习一站通》
相关文章 欢迎阅读

目标读者:中国高校计算机 / 软工 / 网安等专业学生
定位:期末考试复习用,追求通俗但不失严谨,全面覆盖核心考点
声明:本文仅供参考,考试范围参考学校范围
以下内容 如若有误 请告知 谢谢
1. 操作系统概述
1.1 什么是操作系统?
一句话定义 :操作系统(Operating System, OS)是管理计算机硬件资源 、为应用程序提供服务的系统软件。
打个比方:
- 硬件 = 一座毛坯房(CPU 是工人,内存是工作台,磁盘是仓库)
- 操作系统 = 物业公司和装修队,帮你把毛坯房变成可居住的家
- 应用程序 = 住进去的住户
1.2 操作系统的四大核心职能
| 职能 | 一句话解释 |
|---|---|
| 处理机管理 | 决定 "谁用 CPU、用多久" |
| 存储器管理 | 决定 "程序放哪里、怎么放" |
| 设备管理 | 统一管理键盘、鼠标、打印机等外设 |
| 文件管理 | 决定 "数据怎么存、怎么找" |
1.3 操作系统的分层结构
┌─────────────────────────┐
│ 用户 / 应用程序 │ ← 最上层
├─────────────────────────┤
│ 系统调用接口 │ ← 用户态与内核态的分界线
├─────────────────────────┤
│ ┌───────────────┐ │
│ │ 文件系统 │ │
│ ├───────────────┤ │
│ │ 进程管理 │ │ ← 内核核心
│ ├───────────────┤ │
│ │ 内存管理 │ │
│ ├───────────────┤ │
│ │ I/O设备驱动 │ │
│ └───────────────┘ │
├─────────────────────────┤
│ 硬件 │ ← 最底层
└─────────────────────────┘
1.4 用户态 vs 内核态
这是考试必考的概念。
- 用户态(User Mode):运行普通应用程序。权限受限,不能直接访问硬件。
- 内核态(Kernel Mode):运行操作系统内核代码。拥有最高权限,可以执行特权指令。
为什么要区分? 防止应用程序搞破坏。一个普通程序不能随便修改系统关键数据,必须通过系统调用(System Call)向内核 "申请"。
⚡ 考点速记:从用户态切换到内核态有哪三种途径?
- 系统调用(主动)
- 中断(外部设备信号)
- 异常(程序出错,如除零、缺页)
1.5 操作系统类型
| 类型 | 特点 | 代表 |
|---|---|---|
| 批处理系统 | 作业成批提交,无交互 | 早期 IBM 主机 |
| 分时系统 | 多用户轮流使用 CPU,有交互 | Unix |
| 实时系统 | 必须在规定时间内响应 | 航天控制、工业控制 |
| 网络操作系统 | 支持网络通信 | Windows Server |
| 分布式操作系统 | 多台计算机像一个整体 | Google 的集群系统 |
| 嵌入式操作系统 | 轻量、专用 | Linux 嵌入式、FreeRTOS |
2. 进程管理
进程管理是操作系统最核心的模块,也是考试分值最大的部分。
2.1 进程 vs 程序
| 程序(Program) | 进程(Process) | |
|---|---|---|
| 本质 | 静态的指令集合 | 动态的执行实例 |
| 存储 | 存在磁盘上 | 存在内存中 |
| 生命周期 | 永久存在(除非删除) | 有创建、运行、消亡的过程 |
| 比喻 | 菜谱 | 厨师按照菜谱在做菜的过程 |
进程的定义 :进程是程序在一个数据集合上 的一次运行过程,是系统进行资源分配和调度的独立单位。
⚡ 别混淆:一个程序可以对应多个进程(比如你同时打开三个记事本窗口),这叫 "程序多次执行产生多个进程"。
2.2 进程的组成
一个进程在内存中包括:
┌──────────────┐
│ PCB │ ← 进程控制块(Process Control Block),进程的"身份证"
│ (数据段之一) │
├──────────────┤
│ 程序段 │ ← 要执行的代码(Text Segment)
├──────────────┤
│ 数据段 │ ← 全局变量、堆(heap)、栈(stack)
└──────────────┘
PCB 中存储什么?
- 进程 ID(PID)
- 程序计数器(PC)------ 下一条要执行的指令地址
- 寄存器现场(上下文)
- 进程状态
- 内存管理信息
- I/O 状态信息
- CPU 调度信息(优先级等)
⚡ 考点 :PCB 是操作系统感知进程存在的唯一标志。
2.3 进程的五状态模型(必考)

创建
│
▼
┌─────────┐
│ 就绪态 │ ←──────┐
│ (Ready) │ │
└────┬────┘ │
│被调度 │时间片用完
▼ │
┌─────────┐ ┌────┴────┐
│ 运行态 │──▶│ 就绪态 │
│(Running) │ │ (Ready) │
└────┬────┘ └─────────┘
│等待某事件(I/O等)
▼
┌─────────┐
│ 阻塞态 │────等待事件完成──▶ 就绪态
│(Blocked) │
└────┬────┘
│
▼
终止
三个核心状态的转换条件(必背):
| 转换 | 条件 |
|---|---|
| 就绪 → 运行 | 被 CPU 调度程序选中 |
| 运行 → 就绪 | 时间片用完,或被更高优先级进程抢占 |
| 运行 → 阻塞 | 等待某事件(I/O 完成、信号等),主动放弃 CPU |
| 阻塞 → 就绪 | 等待的事件发生(I/O 完成),注意:不是直接变运行! |
2.4 进程调度算法(高频计算题)
2.4.1 先来先服务(FCFS --- First Come First Served)
- 规则:谁先到,谁先被服务
- 特点:非抢占式,实现简单
- 缺点:"护航效应"------ 长进程在前,短进程全得等着
- 适用:批处理系统
2.4.2 短作业优先(SJF --- Shortest Job First)
- 规则:预计运行时间最短的进程优先
- 特点:平均等待时间最短(理论最优)
- 缺点:需要预知运行时间(不现实);长作业可能 "饿死"
- 变体:最短剩余时间优先(SRTF)------ 抢占式版本
2.4.3 优先级调度
- 规则:优先级高的先运行
- 关键问题 :优先级反转------ 高优先级进程等低优先级进程释放资源,而低优先级被中优先级抢占
- 解决方案:优先级继承(Priority Inheritance)
2.4.4 时间片轮转(RR --- Round Robin)
- 规则:每个进程轮流运行固定长度的时间片(Time Quantum)
- 关键:时间片太大 → 退化为 FCFS;时间片太小 → 上下文切换开销过大
- 适用:分时系统
2.4.5 多级反馈队列(Multilevel Feedback Queue)
这是现代操作系统(Windows、Linux)实际采用的算法,面试和考研都喜欢考。
┌──────────┐
│ 新进程 │
└────┬─────┘
▼
┌───────────┐ 时间片=8ms
│ 队列0(RR) │ 最高优先级
└─────┬─────┘
│ 未完成 → 降级
▼
┌───────────┐ 时间片=16ms
│ 队列1(RR) │
└─────┬─────┘
│ 未完成 → 降级
▼
┌───────────┐ 时间片=32ms
│ 队列2(FCFS)│ 最低优先级
└───────────┘
核心思想:
- 短进程优先完成(在高层队列用短时间片)
- 长进程慢慢做(降级到低层队列用长时间片),但不被饿死
2.4.6 调度算法对比表
| 算法 | 抢占? | 平均等待时间 | 饥饿问题 |
|---|---|---|---|
| FCFS | 否 | 大 | 无 |
| SJF | 否 | 最小 | 长进程可能饿死 |
| SRTF | 是 | 最小 | 长进程可能饿死 |
| 优先级 | 均可 | 取决于实现 | 低优先级可能饿死 |
| RR | 是 | 较大 | 无 |
| 多级反馈队列 | 是 | 较小 | 无 |
⚡ 计算题技巧:画甘特图(Gantt Chart)!把每个进程的起止时间标出来,再算等待时间 = 完成时间 - 到达时间 - 运行时间。
2.5 线程(Thread)
2.5.1 线程 vs 进程
| 维度 | 进程 | 线程 |
|---|---|---|
| 资源拥有 | 拥有独立资源 | 共享进程资源 |
| 调度单位 | 传统 OS 的调度单位 | 现代 OS 的调度单位 |
| 并发性 | 进程间并发 | 进程内 + 线程间并发 |
| 系统开销 | 创建 / 切换开销大 | 创建 / 切换开销小 |
| 通信 | 需要 IPC 机制 | 可直接读写共享数据 |
| 独立性 | 一个进程崩溃不影响其他 | 一个线程崩溃可能影响整个进程 |
一句话:进程是资源分配的基本单位,线程是 CPU 调度的基本单位。
⚡ 高频考点 :同一进程的线程共享什么?独享什么? 共享 :代码段、数据段、打开的文件、信号处理函数、当前工作目录 独享:线程 ID、程序计数器(PC)、寄存器组、栈空间、错误码(errno)
2.5.2 线程的实现方式
| 类型 | 实现位置 | 优点 | 缺点 |
|---|---|---|---|
| 用户级线程 | 用户空间的线程库 | 切换快,无需陷入内核 | 一个线程阻塞,整个进程阻塞 |
| 内核级线程 | 内核直接管理 | 一个阻塞不影响其他 | 切换开销较大 |
| 混合模型 | 两者结合 | 兼具两者优点 | 实现复杂 |
2.6 进程间通信(IPC --- Inter-Process Communication)
| 方式 | 速度 | 适用场景 |
|---|---|---|
| 管道(Pipe) | 快(内存) | 父子进程、有亲缘关系 |
| 命名管道(FIFO) | 快 | 无亲缘关系的进程 |
| 消息队列 | 较快 | 结构化数据传递 |
| 共享内存 | 最快 | 大量数据共享(需配合信号量同步) |
| 信号量(Semaphore) | --- | 同步互斥,不传数据 |
| 信号(Signal) | --- | 异步通知(如 Ctrl+C) |
| Socket | 较慢(可能走网络) | 跨网络通信 |
3. 内存管理
3.1 为什么需要内存管理?
- 内存是稀缺资源,多个进程争用
- 需要保护:进程 A 不能访问进程 B 的内存
- 需要扩充:程序所需内存可能大于物理内存(虚拟内存)
3.2 连续分配方式
3.2.1 单一连续分配
最简单:内存只分给一个程序用。早期 DOS 就这样。
3.2.2 固定分区分配
把内存预先划分为固定大小的分区。 问题:内部碎片(分给你的比你用的大)
3.2.3 动态分区分配
按需分配,产生外部碎片。
四种分配算法(必考):
| 算法 | 策略 | 特点 |
|---|---|---|
| 首次适应(First Fit) | 找到第一个够大的空闲分区就分配 | 简单快速,低地址碎片多 |
| 循环首次适应(Next Fit) | 从上次分配的位置继续找 | 空闲分区分布更均匀 |
| 最佳适应(Best Fit) | 找到最接近需求大小的分区 | 产生最多小碎片 |
| 最差适应(Worst Fit) | 找到最大的空闲分区 | 大分区被切碎 |
⚡ 记忆口诀:首次从 0 开始找,循环从上继续找,最佳找最接近的,最差找最大的。
3.3 离散分配方式 = 分页 + 分段 + 段页式
3.3.1 分页存储管理(Paging)------ 超级重点
核心思想:把内存和进程都切成同样大小的小块。
-
物理内存被切成 页框 / 页帧(Frame)
-
进程逻辑地址空间被切成 页(Page)
-
页和页框大小相同,任意页可以装入任意空闲页框
逻辑地址 A 的拆分(假设页面大小 4KB = 2^12):
┌─────────────┬─────────────┐
│ 页号 P │ 页内偏移 W │
│ (高位) │ (低12位) │
└─────────────┴─────────────┘P = A / 页面大小(整数除法)
W = A % 页面大小(取余)
地址变换过程(必画流程图):

逻辑地址 → [页号P | 偏移W]
│
▼
┌──────────────────┐
│ 页表(Page Table)│ 每个进程一张页表
│ 页号 → 页框号 │
│ P → f │
└────────┬─────────┘
│
▼
物理地址 = f × 页面大小 + W
页表项中除了页框号,还有:
- 有效位:该页是否在内存中(1 = 在,0 = 不在,产生缺页中断)
- 修改位(脏位):该页是否被修改过(页面置换时判断需不需要写回磁盘)
- 访问位:该页最近是否被访问过(用于页面置换算法)
- 保护位:读 / 写 / 执行权限
⚡ 考点 :分页不会有外部碎片,但每个进程最后一页可能有内部碎片(平均半页)。
3.3.2 快表(TLB --- Translation Lookaside Buffer)
页表存在内存中,每次访问数据需要两次访存:
- 先查页表(一次访存)
- 再访问目标数据(又一次访存)
TLB 是 CPU 内部的一个高速缓存,存放最近使用的页表项。
有了TLB后:
CPU要先访问的数据地址
│
▼
┌──────┐ 命中(大多数情况)→ 直接拿到页框号,一次访存即可
│ TLB │
└──┬───┘ 未命中 → 查内存中的页表 → 更新TLB → 访问数据
│
▼
访问数据
有效访问时间计算(必考题):
EAT = 命中率 × (TLB访问时间 + 一次访存时间)
+ (1-命中率) × (TLB访问时间 + 两次访存时间)
3.3.3 多级页表
问题:32 位系统,页大小 4KB,页表有多大?
- 页号位数 = 32 - 12 = 20 位 → 2^20 = 1M 个页表项
- 每个页表项 4 字节 → 页表大小 = 4MB
- 每个进程都要一张页表,内存浪费严重!
解决方案 ------ 二级页表:
32位逻辑地址:
┌──────────┬──────────┬──────────┐
│ 一级页号 │ 二级页号 │ 页内偏移 │
│ (10位) │ (10位) │ (12位) │
└──────────┴──────────┴──────────┘
外层页表(一级) → 内层页表(二级) → 物理页框
↓ ↓
常驻内存 按需调入/调出内存
现在 64 位系统更多级(Linux 用 4 级、5 级页表),原理相同。
3.3.4 分段存储管理(Segmentation)
与分页的本质区别:
| 分页 | 分段 | |
|---|---|---|
| 划分依据 | 固定大小(物理驱动) | 逻辑单元(程序员视角) |
| 程序员感知 | 不可见 | 可见 |
| 目的 | 提高内存利用率 | 方便编程 / 共享 / 保护 |
| 碎片 | 内部碎片 | 外部碎片 |
逻辑地址 = [段号S | 段内偏移W]
段表(Segment Table):
┌──────┬──────┬────────┐
│ 段号 │ 段长 │ 段基址 │
├──────┼──────┼────────┤
│ 0 │ 1KB │ 0x1000 │
│ 1 │ 500B │ 0x2000 │
└──────┴──────┴────────┘
物理地址 = 段基址 + 偏移(需检查偏移 < 段长,否则越界中断)
3.3.5 段页式存储管理
段页式结合了两者的优点:先分段,每段再分页。
逻辑地址 = [段号S | 段内页号P | 页内偏移W]
每次数据访问需要三次访存:
- 查段表
- 查页表
- 访问数据
(所以必须用 TLB 来加速)
3.4 虚拟内存(Virtual Memory)------ 超级重点
3.4.1 核心思想
程序不需要全部装入内存才能运行。
- 只需要把当前要用到的部分装入内存
- 暂时不用的放在磁盘(交换区 / Swap)
- 用到了却不在内存 → 缺页中断 → 调入
3.4.2 局部性原理(虚拟内存的理论基础)
| 类型 | 含义 | 例子 |
|---|---|---|
| 时间局部性 | 刚被访问的地址,不久后会再次被访问 | 循环中的指令、变量 |
| 空间局部性 | 某地址被访问后,其附近的地址很快也会被访问 | 顺序执行、数组遍历 |
因为程序有局部性,虚拟内存才有效 ------ 缺页不会过于频繁。
3.4.3 请求分页系统
在基本分页的基础上增加了:
- 缺页中断:访问的页不在内存时触发
- 页面置换:内存满了需要换出某些页
3.4.4 页面置换算法(必考计算题)
| 算法 | 策略 | 特点 |
|---|---|---|
| OPT(最佳置换) | 淘汰将来最长时间不用的页 | 理论最优,无法实现,仅作比较基准 |
| FIFO | 淘汰最早进入内存的页 | 简单,但可能有Belady 异常 |
| LRU(最近最久未使用) | 淘汰最长时间没有被访问的页 | 效果很好,近似 OPT,但实现代价高 |
| Clock / NRU(最近未用) | 每页一个访问位,像时钟指针扫描 | LRU 的近似算法,实用 |
| 改进型 Clock | 再加一个修改位 | 优先淘汰 "未访问 + 未修改" 的页 |
⚡ Belady 异常 :FIFO 算法特有的现象 ------ 物理页框数增多,缺页次数反而增加。LRU 和 OPT 没有 Belady 异常(它们属于栈算法)。
缺页率计算(必考题套路):
给定:页面访问序列 + 物理块数 + 置换算法
要求:画出每次访问的页面状态,统计缺页次数
缺页率 = 缺页次数 / 总访问次数
注意:首次调入也算缺页!
3.4.5 抖动(Thrashing)
现象 :系统频繁换入换出页面,CPU 大部分时间都在等待换页,实际效率极低。 原因 :分配的物理块数太少,不足以容纳当前活跃访问集合(工作集) 解决:增大物理块数,或用工作集模型控制并发度
4. 文件系统
4.1 文件系统的基本概念
文件:具有符号名的一组相关信息的集合。
文件系统的层次结构:
┌──────────────────┐
│ 用户接口(shell) │
├──────────────────┤
│ 文件目录系统 │
├──────────────────┤
│ 存取控制模块 │
├──────────────────┤
│ 逻辑文件系统 │
├──────────────────┤
│ 物理文件系统 │
├──────────────────┤
│ 设备驱动程序 │
└──────────────────┘
4.2 文件的逻辑结构
| 类型 | 描述 | 例子 |
|---|---|---|
| 无结构文件(流式文件) | 字节序列 | 源程序、文本文件 |
| 有结构文件(记录式文件) | 定长 / 变长记录 | 数据库文件 |
文件的存取方式:
- 顺序存取:从头到尾依次读取(磁带)
- 直接存取(随机存取):直接跳到任意位置读取(磁盘)
- 索引存取:通过索引表定位记录(数据库常用)
4.3 文件的物理结构(磁盘上怎么存)------ 重点
4.3.1 连续分配
- 文件占连续的磁盘块
- 优点:顺序访问快,实现简单
- 缺点:外部碎片,文件增长困难
- 类似内存的连续分配
4.3.2 链接分配
-
每个磁盘块有一个指针指向下一块
-
隐式链接:指针在磁盘块内部(如 FAT 文件系统的基础)
-
显式链接(FAT):把所有指针集中放在文件分配表(FAT)中
-
优点:无外部碎片,文件可动态增长
-
缺点:随机访问慢(隐式链接),FAT 表太大(显式链接)
FAT表的工作方式:
┌─────┬─────┬─────┬─────┬─────┐
│块号 │ 0 │ 1 │ 2 │ 3 │
├─────┼─────┼─────┼─────┼─────┤
│FAT值│ EOF │ 2 │ 3 │ EOF │
└─────┴─────┴─────┴─────┴─────┘文件由块1和块2和块3组成:
块1(FAT=2) → 块2(FAT=3) → 块3(FAT=EOF)
4.3.3 索引分配
-
每个文件有一个索引块,存放该文件所有数据块的地址
-
优点:支持随机访问,无外部碎片
-
缺点:索引块本身占用空间
-
现代 OS 常用 ,UNIX/Linux 的 inode 就是这个思想
inode 结构(以Unix为例):
┌──────────────────────┐
│ 文件元数据 │ ← 大小、权限、时间戳等
├──────────────────────┤
│ 直接块 [0]~[11] │ ← 12个直接指针,指向数据块
├──────────────────────┤
│ 一级间接块 │ ← 指向一个装满指针的块
├──────────────────────┤
│ 二级间接块 │ ← 指向装满一级间接指针的块
├──────────────────────┤
│ 三级间接块 │ ← 极少用到
└──────────────────────┘
⚡ 考点:计算单个文件最大支持多大。给定块大小和指针大小,就能算出来。
4.4 文件目录
目录的本质 :也是一个文件,存的是(文件名 → 文件控制块)的映射表。
目录结构演变:
单级目录 → 两级目录 → 树形目录(现代OS通用)→ 无环图目录(支持硬链接/软链接)
文件控制块(FCB) = 文件的 "身份证",包含:
- 文件名、类型
- 物理地址
- 大小
- 访问权限
- 创建 / 修改 / 访问时间
注意:Unix 中 FCB 和信息分开 ------ 文件名在目录项中,其他信息在 inode 中。这是实现硬链接的关键!
4.5 硬链接 vs 软链接(符号链接)
| 硬链接(Hard Link) | 软链接(Symbolic Link) | |
|---|---|---|
| 本质 | 多个目录项指向同一个 inode | 一个独立文件,内容是目标路径字符串 |
| 跨文件系统 | 不可以 | 可以 |
| 删除原文件 | 链接仍有效 | 链接失效(断链) |
| 创建方式 | ln src dst |
ln -s src dst |
| 类比 | 一个房子有多个门牌号 | 路牌上写着 "XX 在那边" |
4.6 空闲空间管理
| 方法 | 原理 | 特点 |
|---|---|---|
| 空闲表法 | 维护一张 "空闲区表" | 类似内存动态分区管理 |
| 空闲链表法 | 把所有空闲块串成一个链表 | 实现简单,但效率低 |
| 位示图法(Bitmap) | 每一位表示一个块(1 = 占用,0 = 空闲) | 最常用,空间开销小,容易找到连续空闲块 |
| 成组链接法 | 结合空闲表和链表 | Unix/Linux 采用 |
⚡ 计算题:位示图占用空间 = 磁盘块总数 / 8 字节。如 1TB 磁盘,块大小 4KB,位示图约 32MB。
4.7 磁盘调度算法(计算题)
| 算法 | 策略 | 特点 |
|---|---|---|
| FCFS | 按请求顺序服务 | 公平但性能差 |
| SSTF(最短寻道时间优先) | 离当前磁道最近的先服务 | 性能好,但可能饿死 |
| SCAN(电梯算法) | 磁头单向移动到底再折返 | 经典实用 |
| C-SCAN | 单向移动到底后快速返回起点 | 各磁道等待时间更均匀 |
| LOOK / C-LOOK | 不需要走到最内 / 最外,最远请求处即折返 | SCAN 的优化版 |
⚡ 计算技巧:画出磁道位置图,追踪磁头移动轨迹,累加跨越的磁道数。
5. I/O 设备管理
5.1 I/O 设备的分类
| 分类维度 | 类型 |
|---|---|
| 传输速率 | 低速(键盘鼠标)、中速(打印机)、高速(磁盘) |
| 信息交换单位 | 块设备 (磁盘,按块传输)、字符设备(键盘,按字节流传输) |
| 共享属性 | 独占设备、共享设备、虚拟设备 |
5.2 I/O 控制方式(按发展历程,越往后 CPU 干预越少)
| 方式 | CPU 参与程度 | 说明 |
|---|---|---|
| 程序直接控制(轮询) | CPU 全程参与,反复检查设备状态 | 效率极低,CPU 与 I/O 完全串行 |
| 中断驱动 | I/O 完成时发中断通知 CPU | CPU 和 I/O 可部分并行 |
| DMA(直接存储器访问) | CPU 只需交代任务,DMA 控制器自行完成数据传输 | CPU 与 I/O 高度并行 |
| 通道控制 | 通道是一个小型专用处理器,独立执行通道程序 | 大型机用,CPU 彻底解放 |
⚡ 考点 :DMA 传输,CPU 只在开始时设置参数,结束时收中断通知 ------ 中间过程完全不参与。DMA 适合块设备的大批量数据传输。
5.3 SPOOLing 技术(假脱机)
全称:Simultaneous Peripheral Operations OnLine(外部设备联机并行操作)
核心思想:用磁盘做缓冲,把独占设备变成 "虚拟" 共享设备。
传统方式:进程 → 打印机(独占,其他进程等着)
SPOOLing:进程 → 磁盘上的输出井(并发写入)→ 打印机守护进程逐个取出打印
组成:
- 输入井 / 输出井:磁盘上的一块区域
- 输入进程 / 输出进程:负责在井和设备之间搬运数据
⚡ 典型应用:共享打印机。所有用户都把打印任务发到输出井,然后排队打印。
5.4 缓冲技术
为什么需要缓冲?
- 缓和 CPU(快)和 I/O 设备(慢)之间的速度矛盾
- 减少对设备的访问次数
- 提高 CPU 与 I/O 的并行度
| 类型 | 描述 |
|---|---|
| 单缓冲 | 一个缓冲区,CPU 和设备交替使用 |
| 双缓冲 | 两个缓冲区,一个用于设备传输,一个用于 CPU 处理,可并行 |
| 循环缓冲 | 多个缓冲区组成环,适合连续数据流 |
| 缓冲池 | 系统统一管理多个缓冲区,按需分配 |
6. 用户接口与 Shell
6.1 用户接口的分类
用户接口
├── 命令接口
│ ├── 联机命令接口(CLI)------ 用户说一句,系统做一句
│ └── 脱机命令接口(批处理)------ 用户写好脚本,系统批量执行
├── 程序接口(系统调用)------ 程序调用OS服务
└── 图形用户接口(GUI)------ 图形化操作
6.2 系统调用(System Call)
系统调用是用户程序访问内核服务的唯一入口。
常见系统调用分类:
| 类别 | 典型系统调用 |
|---|---|
| 进程控制 | fork(), exit(), wait(), exec() |
| 文件操作 | open(), read(), write(), close(), lseek() |
| 设备管理 | ioctl() |
| 信息维护 | getpid(), alarm(), sleep() |
| 通信 | pipe(), shmget(), mmap() |
系统调用过程(以 read () 为例):
用户程序: read(fd, buf, n)
│
▼ (1) 把参数和系统调用号放入寄存器
│
▼ (2) 执行 trap/syscall 指令(触发软中断)
───────┴──────── 用户态 → 内核态 ──────────
│
▼ (3) 内核根据系统调用号查表,找到 sys_read()
│
▼ (4) 执行 sys_read(),完成实际读取
│
▼ (5) 返回结果,恢复用户态
───────┴──────── 内核态 → 用户态 ──────────
│
▼
用户程序: 拿到返回值,继续执行
6.3 Shell 是什么?
Shell 是命令解释器,位于用户和操作系统内核之间。
工作原理:
用户输入命令 → Shell解析 → 查找对应程序 → fork子进程 → exec加载程序 → 等待子进程结束 → 显示结果 → 等待下一条命令
⚡ 常见面试题 :在 Shell 中输入
ls后发生了什么?
- Shell 解析命令字符串
- fork () 创建一个子进程
- 子进程 exec () 加载 /bin/ls 程序
- 父进程 wait () 等待子进程结束
- 子进程执行 ls 的代码,输出结果后 exit ()
- 父进程重新显示提示符
7. 死锁

7.1 死锁的定义
死锁 :一组进程中的每个进程都在等待只有该组中其他进程才能释放的资源,导致所有进程都无法推进。
现实类比:两个人吃饭,只有一双筷子。每人拿一只,都在等对方放下 ------ 那就谁都吃不了。
7.2 死锁的四个必要条件(必背,常考简答)
死锁必须同时满足以下四个条件(缺一个都不会死锁):
- 互斥条件:资源不能同时被多个进程共享(至少有一个资源是独占的)
- 请求和保持条件:进程已持有资源,又去申请新资源(吃着碗里的,看着锅里的)
- 不可抢占条件:已分配的资源不能被强行夺走(只能进程主动释放)
- 循环等待条件:存在进程 - 资源的循环等待链(P1 等 P2,P2 等 P3,P3 等 P1)
7.3 死锁的处理策略
┌── 预防(Prevention) ------ 破坏四个必要条件之一
│
死锁处理 ──┼── 避免(Avoidance) ------ 银行家算法,动态判断是否分配
│
├── 检测(Detection) ------ 资源分配图 + 死锁检测算法
│
└── 解除(Recovery) ------ 终止进程 或 剥夺资源
7.3.1 死锁预防 ------ 破坏四个必要条件
| 破坏的条件 | 策略 | 问题 |
|---|---|---|
| 互斥 | 让资源共享 | 不是所有资源都能共享(如打印机) |
| 请求和保持 | 一次性分配所有资源 | 资源利用率低,可能饥饿 |
| 不可抢占 | 可强行剥夺 | 实现复杂,可能丢数据 |
| 循环等待 | 资源有序分配(给资源编号,只能按编号递增申请) | 编号可能不合理 |
7.3.2 死锁避免 ------ 银行家算法(计算题重点)
核心思想:在分配之前,先 "预演" 一下 ------ 分配后系统是否还处于安全状态?安全就分,不安全就不分。
数据结构:
- Available:系统当前可用资源向量
- Max:每个进程的最大需求矩阵
- Allocation:已分配矩阵
- Need:还需资源矩阵 = Max - Allocation
安全性算法:
- 找一个 Need ≤ Available 的进程(能完成)
- 假设它完成,释放资源,Available += 它的 Allocation
- 标记它完成,重复找下一个
- 全部标记完成 → 安全 ;有进程不能完成 → 不安全
⚡ 解题步骤 :先算出 Need 矩阵,再按安全性算法一步步推演。分配资源前先 "试探性分配",然后检查安全状态。
7.3.3 资源分配图(Resource Allocation Graph)
进程 P 资源 R
○ □
分配边:R ──→ P (资源已分配给进程)
请求边:P ──→ R (进程请求资源)
图中存在环路不一定死锁
(如果每类资源有多个实例,环路只是死锁的必要不充分条件)
但如果每类资源只有一个实例,环路出现 = 死锁
8. 并发与同步
8.1 临界区(Critical Section)
临界区:访问共享资源的那段代码。
临界区的四个要求(必背):
- 互斥进入(Mutual Exclusion):同一时间最多一个进程在临界区
- 有空让进(Progress):临界区空闲时,想进入的进程必须能选出一个进去
- 有限等待(Bounded Waiting):一个进程从请求进入临界区到实际进入,等待时间有限
- 让权等待(不强制,但最好有):进不去临界区时,应该释放 CPU,不要忙等
8.2 互斥的实现方式
| 方式 | 说明 | 问题 |
|---|---|---|
| 关中断 | 关中断就不会被调度走 | 只能在内核态用,多 CPU 无效 |
| 软件方法(Peterson 算法) | 纯软件实现 | 复杂且可能忙等 |
| 硬件指令(Test-and-Set, Swap) | 原子指令 | 简单但可能忙等 |
| 信号量(Semaphore) | OS 提供的同步工具 | 最常用 |
| 管程(Monitor) | 更高级的同步工具 | 主流编程语言都支持 |
8.3 信号量(Semaphore)------ 大题重点
// P 操作(荷兰语 Proberen = 尝试),也叫 wait() 或 down()
P(S) {
while (S <= 0) ; // 等待(原子性由OS保证)
S--;
}
// V 操作(荷兰语 Verhogen = 增加),也叫 signal() 或 up()
V(S) {
S++;
}
信号量的应用:
| 应用 | 初始值 | 用法 |
|---|---|---|
| 互斥 | S=1(二元信号量) | P (mutex) ... 临界区... V (mutex) |
| 同步(先来后到) | S=0 | 等的一方 P,做完的一方 V |
| 资源计数 | S=N(N 个资源) | P 获取资源,V 归还资源 |
⚡ P/V 操作解题口诀:
- P:申请资源 / 等待事件
- V:释放资源 / 通知事件
- 互斥的 P 和 V 在同一个进程 中,同步的 P 和 V 在不同进程中
8.4 经典同步问题(必考)
8.4.1 生产者 - 消费者问题
Semaphore mutex = 1; // 互斥访问缓冲区
Semaphore empty = N; // 空位数量
Semaphore full = 0; // 产品数量
// 生产者
Producer() {
produce item;
P(empty); // 等空位
P(mutex); // 互斥进入
put item;
V(mutex);
V(full); // 产品+1,唤醒消费者
}
// 消费者
Consumer() {
P(full); // 等产品
P(mutex);
get item;
V(mutex);
V(empty); // 空位+1,唤醒生产者
consume item;
}
⚡ 关键:两个 P 操作的顺序不能颠倒!先 P (empty/full) 再 P (mutex),否则会死锁。
8.4.2 读者 - 写者问题
- 读者优先:只要有读者在读,新读者可以进来(写者可能饿死)
- 写者优先:有写者等待时,新读者必须排队
- 公平竞争:按到达顺序
8.4.3 哲学家进餐问题
五位哲学家围一桌,每两位之间一根筷子,每人需要两根筷子才能吃饭。
问题:如果每人同时拿左手边的筷子 → 死锁。
解决:
- 最多允许四位哲学家同时拿筷子
- 奇数号先拿左,偶数号先拿右
- 两根筷子同时拿(用互斥信号量保护取筷子操作)
8.5 管程(Monitor)
管程 = 共享数据结构 + 操作这些结构的过程 + 同步机制
管程封装了:
1. 共享变量(数据结构)
2. 操作共享变量的方法(过程/函数)
3. 条件变量(Condition Variables)
- wait(condition):把自己挂在这个条件上等待
- signal(condition):唤醒一个等待这个条件的进程
管程 vs 信号量:
- 信号量对程序员要求高(P/V 分散在各处,容易出错)
- 管程把同步逻辑封装在一起,更安全、更易维护
- Java 的
synchronized、C# 的lock本质上就是管程思想
9. 虚拟化技术
9.1 什么是虚拟化?
一句话:把一台物理机变成多台 "虚拟机",每台都以为自己独占硬件。
9.2 虚拟化的类型
| 类型 | 说明 | 例子 |
|---|---|---|
| 裸金属虚拟化(Type 1) | Hypervisor 直接运行在硬件上 | VMware ESXi, KVM, Hyper-V |
| 宿主型虚拟化(Type 2) | Hypervisor 运行在宿主 OS 上 | VirtualBox, VMware Workstation |
| 容器(Container) | 共享宿主机 OS 内核,只隔离应用空间 | Docker, LXC |
9.3 虚拟化的核心技术
| 技术 | 说明 |
|---|---|
| CPU 虚拟化 | 特权指令的翻译和模拟(陷入 - 模拟 / 二进制翻译 / 硬件辅助(Intel VT-x, AMD-V)) |
| 内存虚拟化 | 两层地址映射:Guest VA → Guest PA → Host PA(影子页表 / EPT / NPT) |
| I/O 虚拟化 | 设备模拟、半虚拟化驱动(virtio)、设备直通(SR-IOV) |
⚡ 考试角度:重点理解为什么虚拟化需要 "陷入并模拟" 特权指令 ------ 因为 Guest OS 以为自己在内核态,但实际上运行在用户态。
10. 安全与保护
10.1 操作系统的安全目标
| 目标 | 含义 |
|---|---|
| 机密性 | 不泄露给未授权者 |
| 完整性 | 不被未授权修改 |
| 可用性 | 合法用户能正常使用(DDoS 攻击破坏的就是可用性) |
10.2 保护机制
| 机制 | 说明 |
|---|---|
| 访问控制矩阵 | 主体(用户 / 进程)× 客体(文件 / 设备)× 权限(r/w/x) |
| 访问控制列表(ACL) | 每个客体附带一张 "谁可以怎么访问我" 的列表(Linux 文件权限) |
| 能力表(Capability) | 每个主体持有一张 "我能访问什么" 的列表 |
Linux 文件权限表示:
-rwxr-xr-- 1 alice cs 4096 Jun 26 10:00 hello.c
│└┬┘└┬┘└┬┘
│ │ │ └── 其他人权限 (r--)
│ │ └───── 同组人权限 (r-x)
│ └──────── 所有者权限 (rwx)
└─────────── 文件类型 (-普通文件, d目录, l符号链接)
10.3 身份认证
| 方式 | 例子 |
|---|---|
| 你知道什么 | 密码 |
| 你有什么 | U 盾、手机令牌、门禁卡 |
| 你是什么 | 指纹、虹膜、人脸 |
多因素认证(MFA):组合两种以上方式。
11. 常见考题类型与答题技巧
11.1 题型分布(以多数高校为例)
| 题型 | 分值占比 | 特点 |
|---|---|---|
| 选择题 | 20~30% | 考察概念辨析 |
| 简答题 | 20~30% | 概念解释、原理解释 |
| 计算题 | 20~30% | 调度、页面置换、磁盘调度 |
| 综合分析题(PV 操作等) | 20~30% | 综合运用能力 |
11.2 高频简答题汇总
什么是操作系统?它的主要功能是什么?
操作系统是一组管理计算机硬件与软件资源的系统软件,为用户和应用程序提供统一、便捷的服务接口,是硬件与上层软件之间的中间层。
四大核心功能
- 处理机管理:进程 / 线程调度,分配 CPU 时间,并发控制;
- 存储器管理:内存分配、地址映射、内存保护、虚拟内存扩充;
- 设备管理:缓冲、分配、驱动控制,屏蔽硬件差异;
- 文件管理:文件存储空间管理、目录管理、读写保护。
额外辅助功能:用户接口、系统安全保护。
进程和程序的区别?进程有哪三种基本状态?
进程与程序区别
- 本质不同:程序是静态指令集合,存于磁盘;进程是程序在数据集上的一次动态执行实例,驻留内存;
- 生命周期:程序永久存在,进程有创建、就绪、运行、阻塞、销毁完整生命周期;
- 资源属性:程序不占用运行资源;进程是系统资源分配、调度的独立单位;
- 对应关系:一个程序可生成多个进程(多开软件),一个进程仅对应一套程序代码。
进程三大核心状态
就绪态、运行态、阻塞态
- 就绪:进程已获除 CPU 外全部资源,等待调度;
- 运行:进程占用 CPU 正在执行;
- 阻塞:进程等待 I/O、信号等事件,主动放弃 CPU。
什么是死锁?死锁的四个必要条件是什么?
一组并发进程互相占用对方所需资源,且都不肯释放自身资源,导致所有进程无限等待、无法向前推进的僵局。
四大必要条件(同时满足才会死锁)
- 互斥条件:资源具有独占性,同一时刻仅一个进程使用;
- 请求与保持:进程已持有部分资源,又申请新资源,不释放已有资源;
- 不可剥夺:已分配资源不能被系统强制收回,只能进程主动释放;
- 循环等待:存在进程 - 资源环形等待链,P1 等 P2 资源,P2 等 P3...Pn 等 P1。
分页和分段的区别?
| 对比维度 | 分页 | 分段 |
|---|---|---|
| 划分依据 | 硬件视角,物理固定大小切割 | 程序员逻辑视角,按功能模块划分(代码段、数据段) |
| 地址空间 | 一维线性地址 | 二维地址(段号 + 段内偏移) |
| 碎片问题 | 无外部碎片,存在内部碎片 | 无内部碎片,产生外部碎片 |
| 用户可见 | 对程序员透明,不可感知 | 程序员可见,编程可手动划分段 |
| 共享保护 | 共享粒度为整页,灵活性差 | 可单独共享、保护单个逻辑段,更灵活 |
什么是虚拟内存?它的实现原理是什么?
虚拟内存是一种内存管理技术,将磁盘外存作为内存逻辑延伸,让程序逻辑地址空间远大于物理内存容量,无需将程序全部载入内存即可运行。
实现原理(依托局部性原理)
- 理论基础:局部性原理 时间局部性:近期访问的指令 / 数据短期内会重复访问; 空间局部性:访问某地址,周边相邻地址很快被访问。
- 请求调入:仅加载程序当前需要的页面到内存,其余存放磁盘交换区;
- 缺页中断:访问不在内存的页面时触发中断,操作系统将页面从磁盘调入内存;
- 页面置换:内存空间不足时,按置换算法淘汰部分页面写回磁盘,腾出空间加载新页。
系统调用的过程?用户态切换到内核态的途径?
一、系统调用执行过程(以 read 为例)
- 用户程序封装参数、系统调用编号存入寄存器;
- 执行
trap/syscall软中断指令,触发用户态→内核态切换,保存进程上下文;- 内核根据系统调用号查询系统调用入口表,匹配对应内核处理函数;
- 内核执行内核函数,完成硬件 / 资源操作;
- 处理完成,恢复用户进程上下文,切换回用户态,将执行结果返回应用程序。
二、用户态切换内核态三种途径
- 系统调用(主动):程序主动发起服务请求;
- 外部中断(被动):键盘、磁盘等外设硬件发出中断信号;
- 异常 / 陷阱(被动):程序运行出错,如除零、缺页、地址越界。
SPOOLing 系统的原理?
假脱机技术,Simultaneous Peripheral Operations On-Line。
核心思想
利用磁盘开辟输入井、输出井缓冲区,将独占型物理设备虚拟为共享逻辑设备,实现多进程并发使用独占设备。
工作流程(以打印机输出为例)
- 用户进程不直接操作打印机,将打印数据写入磁盘输出井;
- 常驻后台的输出守护进程,按顺序从输出井取出数据;
- 独占打印机依次打印任务;
组成
输入井 / 输出井(磁盘缓冲)、输入 / 输出缓冲区、守护进程。
作用
解决独占设备无法并发的问题,典型应用:局域网共享打印机。
简述缺页中断的处理过程。
- 进程执行指令,访问逻辑页,查询页表发现有效位为 0,触发缺页中断;
- CPU 保存当前进程上下文,切换至内核中断处理程序;
- 内核根据页表记录的磁盘地址,从交换区读取缺失页面;
- 判断物理内存是否有空页框:
- 有空闲块:直接将页面调入内存,更新页表有效位;
- 无空闲块:执行页面置换算法淘汰一页;若淘汰页修改位为 1,先写回磁盘,再载入新页面;
- 更新 TLB 快表,恢复进程上下文;
- 重新执行触发缺页的指令,正常访问内存数据。
进程间通信方式有哪些?
- 管道 (Pipe):仅支持有亲缘关系父子进程,内存缓冲区单向通信;
- 命名管道 (FIFO):无亲缘进程也可通信,依托文件标识;
- 信号 (Signal):异步轻量通知,传递简单事件,不传输大数据;
- 消息队列:内核维护消息链表,结构化数据,支持多进程收发;
- 共享内存:最快 IPC,多个进程映射同一块物理内存,需信号量配合互斥;
- 信号量:专门用于同步、互斥,不传递业务数据;
- Socket 套接字:支持本地、跨网络进程通信。
简述多级反馈队列调度算法的原理。
多级反馈队列是分时系统主流调度算法,融合时间片轮转、优先级调度,兼顾长短进程效率。
- 系统设置多条优先级递减就绪队列,队列层级越高、优先级越高、时间片越小;
- 新创建进程直接进入最高优先级队列,采用时间片轮转调度;
- 进程在当前队列用完时间片未完成,降级至下一级低优先级队列;
- 低层级队列时间片更大,底层队列采用 FCFS 调度;
- CPU 调度时,优先执行高层队列全部进程,高层队列为空才调度下层;
优点
短进程快速完成、长进程逐步执行不会饥饿,交互与批处理场景适配。
11.3 计算题答题模板
调度计算题
1. 画甘特图(标出每个进程的起止时间)
2. 计算周转时间 = 完成时间 - 到达时间
3. 计算带权周转时间 = 周转时间 / 运行时间
4. 求平均值
页面置换计算题
给出访问序列和物理块数,画出:
物理块1: [ ] → [ ] → [ ] → ...
物理块2: [ ] → [ ] → [ ] → ...
物理块3: [ ] → [ ] → [ ] → ...
访问1 访问2 访问3 ...
缺页标记: × √ × ...
统计缺页次数,算出缺页率
磁盘调度计算题
1. 标出当前磁头位置
2. 按算法的规则逐步移动
3. 累加跨越的磁道数
4. 得出平均寻道长度
11.4 PV 操作解题思路
1. 分析题目中有几个"并发角色"(生产者/消费者、读者/写者等)
2. 确定需要几个信号量:
- 互斥 → 同一类角色之间的互斥(通常用 mutex,初值为1)
- 同步 → 不同类角色之间的协作关系
3. 写出每个角色的流程框架
4. 在正确的位置插入 P/V 操作
5. 检查:
- P/V 是否成对出现?
- 是否有死锁风险?(多个P的顺序是否合理)
- 初始值的设置是否合理?
附录:重要公式和数字速记
| 概念 | 公式 / 数值 |
|---|---|
| 逻辑地址 → 物理地址(分页) | 物理地址 = 页框号 × 页面大小 + 偏移量 |
| 页号 | 页号 = 逻辑地址 / 页面大小(整除) |
| 页内偏移 | 偏移 = 逻辑地址 % 页面大小(取余) |
| 页表大小 | 页表大小 = 页号位数可寻址页数 × 每个页表项大小 |
| 有效访问时间(无 TLB) | EAT = 2 × 内存访问时间(查页表 + 取数据) |
| 有效访问时间(有 TLB) | EAT = α × (T_TLB+T_mem) + (1-α) × (T_TLB+2T_mem) |
| 缺页率 | 缺页率 = 缺页次数 / 总访问次数 |
| 位示图大小 | 位示图字节数 = 磁盘总块数 / 8 |
| 最大文件大小(索引分配) | 根据直接块、间接块的数量和块大小逐级计算 |
最后的话:操作系统是计算机专业的核心课程,理解比死记硬背更重要。建议复习时多做计算题(调度、置换、磁盘),PV 操作题要真正理解信号量的含义而非套模板。基础概念建议画思维导图把各部分串起来。祝期末考试顺利!🎓

