跳转至

第 4 章 内存管理

依据:《操作系统概论》(2017 年版)第 4 章、配套自考大纲及附录答案。下文编号指大纲“考核内容与考核要求”;标注“自编”的算例为学习辅助,不是真题。

复习导航:大纲要求与笔记位置

大纲条目 层次 位置 学完应能做到
1.1–1.2 层次、局部性 识记 第 1 节 解释为何能用小容量高速存储支持大程序
2.1–2.3 链接与装入 领会 第 2 节 区分链接、装入、重定位
3.1–3.3 连续分配与动态分区 识记、简单应用 第 3 节 说明三类连续分配的原理与碎片,用 FF、NF、BF 完成分配与回收合并
4.1–4.2 页、页框、页表与地址映射 识记、综合应用 第 4 节 区分逻辑页和物理页框,拆地址、查页表、拼物理地址
4.3 快表(TLB) 领会 第 5 节 说明命中、未命中与访存性能
4.4 二级分页 综合应用 第 6 节 拆分字段、逐级查表
4.5–4.6 分段、段页式 领会 第 7 节 说明地址结构、越界检查与映射
5.1–5.2 虚拟存储与请求分页硬件 识记、领会 第 8 节 说出定义与四个特征,说明页表项与缺页处理
5.3–5.4 页框分配 识记 第 9 节 说明最少页框、分配和置换范围
5.5 页面置换 领会 第 10 节 逐次跟踪六类算法
5.6–5.7 缺页性能、工作集与抖动 领会、识记 第 11 节 算有效访存时间,说明抖动的原因与预防
6.1–6.3 伙伴系统 领会 第 12 节 说明拆分、分配与释放合并

全章十二节按“分配 → 映射 → 扩充”递进:第 1–3 节铺垫存储层次、重定位与连续分区分配;第 4–7 节讲离散分配下的硬件地址变换(分页、TLB、两级页表、反置页表、分段与段页式);第 8–11 节进入虚拟存储,围绕缺页处理、页面置换和抖动展开;第 12 节补充内核管理物理页框的伙伴系统。

本章学习目标

本章围绕三个问题展开:程序如何分配内存空间,逻辑地址如何转换为物理地址,以及程序不能全部装入主存时,如何利用外存实现虚拟存储。地址转换由操作系统与硬件配合完成。

先区分逻辑地址与物理地址,再区分“缺少连续空间”和“所需页面尚未装入主存”。前者可通过分页离散分配,后者需由缺页处理按需调入,必要时进行页面置换。地址切分、置换状态演进和有效访存时间都应动手推算。

1 存储层次与局部性(1.1–1.2,识记)

存储层次依次为寄存器 → 高速缓存(Cache)→ 内存(主存)→ 外存。靠近 CPU 的层次通常速度更快、每比特成本更高、容量更小;主存保存当前运行所需的程序和数据,外存提供较大容量。

小容量高速存储器能够发挥作用,主要依靠程序的局部性:

  • 时间局部性:近期访问过的指令或数据,随后可能再次访问,如循环体和循环变量。
  • 空间局部性:访问某地址后,随后可能访问相邻地址,如顺序取指、按行遍历数组。

局部性是一种常见倾向,并非保证。访问集中于近期内容或相邻位置时,缓存和按需调页通常有效;无规律地跨大范围访问时,效果可能下降。

2 链接、装入与重定位(2.1–2.3,领会)

一份源代码要真正跑起来,中间得过三道关:

源程序 → 编译/汇编 → 目标模块 → 链接 → 装入模块 → 装入内存 → 执行

链接将分别编译的目标模块组合起来,并解析跨模块的函数和变量引用。装入将可执行模块放入运行时地址空间。重定位则根据实际装入位置调整模块中的地址。

按地址确定或转换的时机,装入方式分为以下三类:

方式 地址何时确定/转换 理解要点
绝对装入 编译或汇编时确定物理地址 程序只能装入指定位置,不便于多道程序共享主存
静态重定位 装入时由软件一次性修改相关地址 无需硬件动态变换;装入后不能直接移动程序
动态重定位 每次访存时由硬件根据重定位寄存器转换地址 运行期间可改变程序的装入位置,是离散分配和虚拟存储的基础之一

链接也分静态和动态。静态链接在装入前将目标模块和所需库函数合成装入模块,调整相对地址并解析外部符号;动态链接则将部分工作推迟到装入时,或运行中首次调用时完成。动态库可供多个进程共享,更新单个模块时也不必重新编译整个程序。

自编例:某进程逻辑地址为 120,动态重定位基址寄存器值为 8000,硬件先核对 120 没有超出界限(段长/上限),确认合法后相加得出物理地址 \(8000 + 120 = 8120\)。

3 连续分配与动态分区(3.1–3.3,识记、简单应用)

早期内存管理要求一道程序在物理内存里占一整段连续空间。按用户区切不切分、分界线动不动,连续分配演进出三种做法:

方式 分配办法 主要问题
单一连续分配 除操作系统占用的系统区外,整个用户区只装一道程序 不能支持多道程序并发,用户区其余部分无法供其他程序使用
固定分区 预先把用户区切成固定块数(大小可相等也可不等),一区装一道 程序比分区小会留下无法利用的内部碎片;程序大于最大分区时无法装入
动态分区 不预先划线,进程来申请多少就从空闲区现切多少 反复分配回收后,分区之间夹杂大量零散小空隙,形成外部碎片

固定分区只需维护一张固定长度的分区说明表,记清各区大小、起址和“已分配/未分配”状态;动态分区的块数和起止位置时刻在变,得用空闲分区表或空闲分区链动态维护,链表的排序方式直接对应下面三种查找算法。

3.1 FF、NF、BF

算法 如何选空闲区 特点
首次适应 FF 空闲链按地址递增排,每次从头找第一个放得下的区 查找快,高地址易保住大块空闲;低地址端会被反复切碎
循环首次适应 NF 接着上次分配停下的位置往后找,到尾端就绕回表头 空闲区分布比 FF 均匀,但常把高地址的大整块提前切散
最佳适应 BF 空闲链按容量递增排,挑能放下的最小那一块 每次切完剩的尾巴最小,结果攒出一堆谁也塞不进的极小外部碎片

自编例:空闲区按地址依次为 (100,100)、(300,50)、(500,200),二元组代表 (起址, 长度)。现申请 40,约定从选中分区的低地址端切出:

  • FF 从头扫,选中 (100,100),切走 [100,140),原空闲区缩为 (140,60)。
  • BF 找最贴合的最小块,选中 (300,50),剩 (340,10)。
  • NF 从上次查找结束的位置继续:若本次从第三块开始,就选中 (500,200),剩余 (540,160)。计算前应先确定上次指针停止的位置。

连续处理多次申请与释放时,每完成一步都要更新空闲表,再处理下一次请求。若切分后的剩余空间小于题设规定的最小剩余阈值,则将整块分配给该进程,不再保留单独的空闲项。

3.2 回收与合并

回收时可将分区写成左闭右开区间 [起址, 起址+长度)。若前一空闲区的右端点等于回收区的左端点,或回收区的右端点等于后一空闲区的左端点,就可合并对应的空闲区。只有地址相邻且都已空闲的区域才能合并。

回收区与空闲区关系 处理
上下都不相邻 插入新的空闲表项
只与前一空闲区相邻 增加前一区长度
只与后一空闲区相邻 修改后一区起址并增加长度
同时与前后相邻 三块合一,删除多余表项

自编例:现有空闲区 [100,140) 和 [180,220),现释放 [140,180)。释放区与前后两块都相邻,因此合并为 [100,220),总长 120,空闲表项比原先减少一条。可用“合并后空闲总长=原空闲总长+本次释放量”检查是否漏算边界。

4 基本分页与地址变换(4.1–4.2,识记、综合应用)

动态分区可能出现空闲总量足够、却没有足够大连续空间的情况。分页将进程逻辑地址空间划分为固定大小的页(页面),将物理内存划分为同样大小的页框(物理块)。各页可存入不同空闲页框,由每个进程的页表记录页号到页框号的映射。基本分页要求运行前装入全部页面;第 8 节的请求分页才允许按需调入。

分页消除了外部碎片,但最后一页可能未装满,形成内部碎片;在通常的平均估计中,浪费约为半页。页较小时,末页浪费减少,但页表增大;页较大时,页表缩小,页内碎片及一次调页带入的无用数据则可能增加。

地址变换按三步走:先按页大小 \(L\) 把逻辑地址 \(A\) 拆成页号 \(p\) 和页内偏移 \(d\),核对页号 \(p\) 没有越过页表长度 \(N\)(合法范围 \(0 \le p < N\)),再以 \(p\) 查页表拿到页框号 \(f\),最后拼出物理地址 \(PA\):

\[ \begin{aligned} p &= \left\lfloor A / L \right\rfloor\\ d &= A \bmod L\\ PA &= f \times L + d \end{aligned} \]

页大小取 \(2^k\) 时,MMU 可直接按二进制位切分地址,无需执行整除和取余:低 \(k\) 位保留为页内偏移 \(d\),其余高位为页号 \(p\)。取得页框号 \(f\) 后,将其放在高位、偏移 \(d\) 放在低位,两段拼接为物理地址。因此,纸面公式中的乘加并不意味着硬件必须执行乘法和加法指令。

自编例:页大小为 \(1\ \text{KB} = 1024\ \text{B}\),逻辑地址为 \(2500\)。页表显示第 2 页映射到第 7 号页框。先拆分逻辑地址:\(2500 = 2 \times 1024 + 452\),所以 \(p=2\)、页内偏移 \(d=452\)。再计算物理地址:\(PA = 7 \times 1024 + 452 = 7620\)。页框号是编号,计算物理地址时要先乘页大小,得到页框的起始字节地址。

把常用的两种页大小按 32 位地址摆出来对照(教材图 4-31 就是这套切位拼接的硬件画法):

页大小 页内偏移取低位 页号取高位 本例拆分
1 KB = 2^10 低 10 位 高 22 位 2500 → 页号 2、偏移 452
4 KB = 2^12 低 12 位 高 20 位 00403005H → 页号 00403H、偏移 005H

5 快表(TLB)与访存性能(4.3,领会)

在页表与数据均位于主存、且没有其他缓存的基本分页模型中,一次数据访问需要两次主存访问:先查页表取得页框号,再访问目标单元。快表(TLB)是 MMU 中的高速缓存,保存近期使用的页表项,以减少地址翻译的开销。

地址转换时先查 TLB:命中即可取得页框号;未命中则查主存页表,并将映射填入 TLB。注意,TLB 未命中只表示缓存中没有该映射,不等于页面不在主存。只有确认缺页后,才需要从外存调入页面。

假设单级页表在主存、先查 TLB 未命中再查主存(串行查询)且页面都在主存,设查 TLB 耗时 \(t\)、单次主存访问耗时 \(m\)、TLB 命中率为 \(h\):

\[ \begin{aligned} \text{命中} &: t + m\\ \text{未命中} &: t + 2m\\ EAT &= h(t+m) + (1-h)(t+2m) = t + (2-h)m \end{aligned} \]

教材例 4-7 代入 \(m = 120\ \text{ns}, t = 20\ \text{ns}, h = 90\%\),得到 \(EAT = 20 + 1.1 \times 120 = 152\ \text{ns}\),小于不设 TLB 时的 \(240\ \text{ns}\)。

这套公式对应“先查 TLB、未命中再查一级页表”的串行路径。题目若规定 TLB 与主存可并行查询,命中耗时可能按 \(\max(t, m)\)(通常记作 \(m\))计算;若采用两级页表,未命中时还需增加一次页表访问。应先画出题设路径,再计算各分支的耗时。

CPU Cache 缓存的是指令和数据本身,TLB 缓存的是虚页号到页框号的地址映射。不同进程的相同虚页号可能对应不同页框,因此进程切换时,需要清除不再适用的 TLB 项,或用地址空间标识(ASID)区分映射。

6 两级页表(4.4,综合应用)

逻辑地址空间较大时,单级页表可能占用较多内存。两级页表将页表再分一层:顶层页目录的每个目录项指向一张二级页表;未使用的逻辑地址范围无需建立对应的二级页表。

6.1 反差算例:多了一级,凭什么反而省内存

参数:32 位逻辑地址空间(4 GB)、页大小 4 KB、页表项 4 B。先算单级页表:

\[ \begin{aligned} \text{页数} &= 4\ \text{GB} / 4\ \text{KB} = 2^{20}\\ \text{页表项数} &= 2^{20}\\ \text{页表大小} &= 2^{20} \times 4\ \text{B} = 4\ \text{MB} \end{aligned} \]

在本例的完整单级页表模型中,需要连续的 4 MB 空间,且即使进程只使用少量地址,也仍需保留完整表项。两级页表用于减少这种稀疏地址空间下的开销。

两级的账分两块:

\[ \begin{aligned} \text{页目录} &= 1024\ \text{项} \times 4\ \text{B} = 4\ \text{KB(正好一页)}\\ \text{每张二级页表} &= 1024\ \text{项} \times 4\ \text{B} = 4\ \text{KB(正好一页)}\\ \text{一张二级页表覆盖} &= 1024 \times 4\ \text{KB} = 4\ \text{MB 逻辑空间} \end{aligned} \]

关键是按需建表:若进程使用的 4 MB 逻辑空间恰好落在同一页目录项覆盖的范围内,只需 1 张二级页表:

\[ 4\ \text{KB(页目录)} + 4\ \text{KB(二级页表)} = 8\ \text{KB} \]

4 MB 到 8 KB,差 512 倍。

两级页表节省空间的前提是逻辑地址空间稀疏。若地址空间全部使用,需要 4 KB + 1024 × 4 KB = 4 MB + 4 KB,反而比单级页表多一个页目录。它的优势在于只为已使用的地址范围建立下级页表,且每张表仅占一页,不必申请大段连续空间。

6.2 地址怎么拆、怎么查

以教材常见的 32 位地址 10 位页目录号 p1 | 10 位二级页号 p2 | 12 位偏移 d 为例:

  • 页大小 2^12=4096 B=4 KB;逻辑地址空间 2^32 B=4 GB。
  • 页目录最多 1024 项,每张二级页表最多 1024 项;一张二级页表覆盖 1024×4 KB=4 MB 逻辑空间。
  • 页表项若为 4 B,每张二级页表占 4 KB。

查表次序是:由页目录第 \(p_1\) 项定位二级页表,再由二级页表第 \(p_2\) 项取得页框号 \(f\)。

\[ \begin{aligned} p_1 &= \left\lfloor A / 2^{22} \right\rfloor\\ p_2 &= \left\lfloor A / 2^{12} \right\rfloor \bmod 1024\\ d &= A \bmod 4096\\ PA &= f \times 4096 + d \end{aligned} \]

自编例:A=00403005H,拆得 p1=1、p2=3、d=5。若目录第 1 项定位某二级页表,该表第 3 项给出页框 2AH,则 PA=2A005H。

三个字段的取法与查表次序列成表,比背公式直白(教材图 4-37、图 4-38 是这两步的图示):

字段 取法 本例(A=00403005H)
页目录号 p1 A 右移 22 位 1
二级页号 p2 A 右移 12 位后对 1024 取余 3
页内偏移 d A 对 4096 取余 5
页框号 f 页目录第 1 项定位二级页表,该表第 3 项 2AH
物理地址 PA f 左移 12 位再加 d 2A005H

无 TLB 且各级表都在内存时,二级分页一次数据访问通常要访存 3 次,依次读页目录、二级页表和目标单元。

6.3 反置页表:怎么建、怎么查

反置页表按物理页框建立表项,而非按各进程的逻辑页建表。物理内存有多少页框,就有多少表项;每项记录该页框所属的进程标识 PID、虚页号 VPN 及保护信息。

表的大小因此与虚拟空间、进程数都脱钩,只跟真实内存有关。4 GB 内存、4 KB 页,页框共 2^20 个,每项 4 B,整张表 4 MB,服务全系统所有进程。

反置页表按页框号排列,但地址转换提供的是 (PID, VPN)。若逐项查找,最坏需访问 2^20 个表项,代价很大。因此通常为 (PID, VPN) 建立哈希表,通过散列找到候选项,并用链地址法等方式处理冲突。

反置页表只记录当前驻留主存的页,系统还需另设结构记录非驻留页的外存位置。共享页也需额外处理:同一页框可能对应多个进程的不同 (PID, VPN),单个表项不能直接容纳所有映射。

反置页表的建法与查法压成一张表:

问题 做法
表项按什么建 每个物理页框一项,与虚拟空间大小、进程数无关
查表方向 用(PID, VPN)反查页框号,与页表方向相反
怎么查得快 先哈希到候选表项,冲突用链地址法
缺页与共享页怎么补 另备外存位置登记;共享页靠额外结构串多组映射

7 分段与段页式(4.5–4.6,领会)

分页按固定大小划分地址空间,不直接体现代码、数据和栈等逻辑边界。分段则按程序的逻辑结构组织:代码段、数据段、栈段各自从 0 编址,长度由内容决定。逻辑地址表示为二维的 (段号 s, 段内偏移 d),段表项记录物理起址 base、段长 length 及读写执行权限。

分段地址转换需要进行段内偏移越界检查:先核对段号 \(s\) 是否在段表范围内,再读取第 \(s\) 项的 base 和 length,确认偏移合法后,将基址与偏移相加。这里使用加法,与分页的按位拼接不同:

\[ 0 \le d < \text{length}, \quad PA = \text{base} + d \]

自编例:2 号段基址 6000、段长 500,访问 (2,120) 落在 [0, 500) 内,物理地址为 \(6000 + 120 = 6120\);而访问 (2,500) 当场触发越界中断,因为段长 500 对应的合法偏移只到 499。

比较 分页 分段
划分依据 固定大小的物理管理单位 程序的逻辑模块
长度 固定(由硬件定) 可变(由程序逻辑定)
程序员视角 透明,一维线性地址由硬件自动切分 可见,二维地址显式给出段号与偏移
碎片 页内碎片(无外部碎片) 段间外部碎片(无内部碎片)
共享与保护 按页硬切,跨页边界不好对齐逻辑模块 按整段赋权或共享代码段,干净自然

段页式结合分段的逻辑组织与分页的离散分配:先将程序分段,再把每段划分为固定大小的页。逻辑地址为 (段号 s, 段内页号 p, 页内偏移 d),先用 s 查段表取得页表起址,再用 p 查页表取得页框号,最后与 d 拼成物理地址。不设 TLB 且两类表均在主存时,一次数据访问需 3 次主存访问(段表 → 页表 → 数据)。与两级页表不同,段页式的第一层表示长度可变、独立受保护的逻辑段;两级页表只是分层索引同一分页地址空间。

8 虚拟存储与请求分页(5.1–5.2,识记、领会)

基本分页和基本分段要求程序全部装入主存后才能运行。虚拟存储利用局部性,先装入当前需要的部分,其余保留在外存;运行中访问未驻留的页面时,再由操作系统调入,必要时换出暂不使用的页面。因此,进程的逻辑地址空间可以大于可用物理内存,其范围仍受地址位数及外存等条件限制。

教材归纳了四个特征:多次性(分批装入)、对换性(运行中允许换入换出)、虚拟性(从逻辑上扩充内存容量)、离散性(物理存放不必连续,为前三者提供基础)。虚拟存储并未增加物理内存;若换页过于频繁,仍会严重降低性能,见第 11 节的抖动。

请求分页的页表项除页框号外,还需要管理信息:状态位(存在位)表示页面是否在主存;访问位 A 记录近期是否访问过,供置换算法参考;修改位 M(脏位)记录调入后是否被改写,干净页可直接淘汰,脏页则需先写回外存;外存地址用于定位待调入的页面。

当一条指令访问到合法但状态位为“不在主存”的页面时,软硬件按五步接力完成缺页中断处理:

  1. 硬件 MMU 查页表发现缺页,触发缺页异常陷入内核,保存现场。
  2. 内核核实访问地址合法后,从页表项或配套结构读出该页在外存的位置。
  3. 查看主存有无空闲页框;若已满,按置换算法挑一页淘汰,看修改位决定是否先写盘。
  4. 启动磁盘 I/O 把目标页读进空闲页框,当前进程阻塞让出 CPU;等磁盘中断报信读完后,改写页表(置存在位、填页框号)并同步失效或更新 TLB,唤醒该进程回就绪队列。
  5. 该进程再次被调度上 CPU 时,重新执行刚才引发缺页的那条指令。

缺页异常与第 2 章的普通外部中断不同:外部中断通常在指令边界处理,返回后执行下一条指令;缺页异常发生在当前指令取指或访存时,调页后需要重新执行本条指令。按本节的整条指令重启模型,若一条指令涉及多个页面,分配的页框应足以容纳这些页面,避免反复缺页而无法完成指令。

9 页框分配与调入策略(5.3–5.4,识记)

请求分页需确定两项策略:分给每个进程多少页框(分配策略),以及缺页置换时可从哪些进程的页框中选择(置换范围)。两者形成以下三种组合。“固定分配+全局置换”不成立,因为从其他进程取得页框会改变各进程持有的页框数:

策略 驻留页框数量 牺牲页来源
固定分配、局部置换 装入时定死,运行期间不变 只能从本进程自己的驻留集里挑
可变分配、全局置换 运行期间随全局置换增减 从全系统可置换页框池里挑,被挑中者少一框、缺页者多一框
可变分配、局部置换 平时不变,缺页率过高或过低时由内核增减配额 只从本进程自己的驻留集里挑

大纲条文里写的“动态分配”就是教材正文说的“可变分配”,答题时认准同一个意思即可。至于初始页框怎么分,常见三种:平均分配、按进程大小成比例分配、按优先权分配(或比例加优先权折中)。

还需区分页面何时调入、从哪调入。缺页后再调入称为请求调页;利用空间局部性提前调入预计会用到的页,称为预调页。教材模型中,文件区较分散,对换区(Swap)连续分配、读写较快。若对换区足够大,可先复制程序,之后从对换区调页;若不足,则未修改页从文件区调入,修改页换出到对换区,后续再从对换区调入。

10 页面置换算法(5.5,领会)

页框已满且需调入新页时,系统要选择一个页面换出;替换策略会影响缺页率。大纲要求领会六种算法:

算法 淘汰依据 易错点
OPT 最佳 淘汰将来最长时间不再用(或永不再用)的页 需要预知未来访问序列,用作理论性能对照
FIFO 先进先出 淘汰最早装进内存的那一页 命中不改排队次序;有 Belady 异常(多给页框缺页次数反倒变多)
LRU 最近最久未使用 淘汰过去最长时间没被碰过的页 性能贴近 OPT 且无 Belady 异常,但每次命中都得更新先后次序,硬件开销大
LFU 最少使用 淘汰累计访问次数最少的页 只统计次数,不考虑最近访问时间;历史高频页可能长期保留,常配合定期右移衰减
简单 CLOCK 循环指针扫访问位 A 装入或访问置 A=1;淘汰时从当前指针扫,见 1 清 0 放过,见 0 当场换出并把指针推向下一格
改进 CLOCK 同时看访问位 A 和修改位 M 宁可淘汰干净页省一次写盘,分四档优先级扫描

名称需要按算法定义区分:大纲中的“最近最少使用”对应按次数统计的 LFU;LRU 则是“最近最久未使用”。前者比较访问频次,后者比较距上次访问的时间。

改进型 CLOCK 按 (A, M) 区分四类页面:(0,0) 最近未用且干净,优先淘汰;其次为 (0,1)、(1,0) 和 (1,1)。教材采用两轮扫描:第一轮寻找 (0,0),不改动 A 位;若未找到,第二轮寻找 (0,1),并将经过页面的 A 位清 0。仍未找到时,重复上述过程,利用已更新的访问位继续选择。

教材还介绍两种改进方法:附加引用位算法为每页设置一个 8 位移位寄存器,定期右移,以访问历史近似 LRU;页面缓冲算法(PBA)保留空闲页链表和修改页链表,暂缓覆写淘汰页。若页面很快再次被访问,可直接恢复,省去读盘;修改页也可集中写回。

10.1 自编逐步例:FIFO 与 LRU

3 个页框初始为空,访问串 1,2,3,1,4,1,2。表中固定列顺序表示页框位置,缺包括首次装入;无空闲页框时才发生淘汰。

次序 访问 FIFO 页框 FIFO LRU 页框 LRU
1 1 1,-,- 缺 1,-,- 缺
2 2 1,2,- 缺 1,2,- 缺
3 3 1,2,3 缺 1,2,3 缺
4 1 1,2,3 中 1,2,3 中
5 4 4,2,3 缺,淘汰 1 1,4,3 缺,淘汰 2
6 1 4,1,3 缺,淘汰 2 1,4,3 中
7 2 4,1,2 缺,淘汰 3 1,4,2 缺,淘汰 3

FIFO 缺页 6 次、置换 3 次;LRU 缺页 5 次、置换 2 次。缺页率分别为 6/7、5/7。OPT 在本串第 5 步淘汰页 3(其后不再访问),合计缺页 4 次。

10.2 状态演进表:补记淘汰顺序

10.1 记录的是固定页框里放了谁;选淘汰页时,还要另记一条顺序。FIFO 按装入时间排列,命中不调整;LRU 按最近访问时间排列,每次访问都把该页记为最新。更新次序只需维护管理信息,不需要搬动页框里的数据。

下面继续使用同一序列。两条顺序都从左到右表示“最早 → 最新”;页框已满且发生缺页时,淘汰左端页。

步骤 访问页 FIFO 装入顺序 LRU 最近访问顺序 本步关键动作
1 1 1 1 首次装入
2 2 1,2 1,2 使用空页框
3 3 1,2,3 1,2,3 空页框用尽
4 1 1,2,3 2,3,1 都命中;只有 LRU 更新次序
5 4 2,3,4 3,1,4 FIFO 淘汰 1,LRU 淘汰 2
6 1 3,4,1 3,4,1 FIFO 缺页并淘汰 2;LRU 命中
7 2 4,1,2 4,1,2 都缺页并淘汰 3

FIFO 共缺页 6 次、置换 3 次;LRU 共缺页 5 次、置换 2 次。第 4 步命中后是否更新次序,决定了第 5 步淘汰谁,也决定了第 6 步是否再次缺页。

11 有效访存时间、工作集与抖动(5.6–5.7,领会、识记)

有效访存时间(EAT)会受到缺页率 \(p\) 的影响。设页面在内存时的正常访问时间为 \(m\),缺页处理的总时间 \(F\) 已包含页面调入后的那次访存,则

\[EAT = (1-p)m + pF\]

若题目给出的缺页开销 \(S\) 不包含最后一次访存,则使用 \(EAT = m + pS\)。

自编例:主存访问时间 \(m = 100\ \text{ns}\),缺页总耗时 \(F = 10\ \text{ms} = 10\,000\,000\ \text{ns}\)。缺页率为十万分之一(\(p = 10^{-5}\))时,

\[EAT = (1 - 10^{-5}) \times 100 + 10^{-5} \times 10\,000\,000 \approx 200\ \text{ns}\]

结果是正常访存时间的两倍。原因是一次缺页处理约等于十万次正常访存;即使缺页率很低,也会明显拉高平均时间。

进程需要多少页框,可用工作集 \(W(t, \Delta)\) 估计。Denning 将它定义为时刻 \(t\) 之前、长度为 \(\Delta\) 的窗口内访问过的不同页面集合;工作集大小 \(|W(t, \Delta)|\) 是集合中的页面数。窗口可按时间或最近访问次数定义,以题设为准。例如,最近 5 次访问为 1, 2, 1, 3, 2 时,工作集为 {1, 2, 3},大小为 3,窗口长度为 5。

若分配的页框不足以容纳进程的活跃工作集,页面会频繁换入换出,使进程大部分时间用于调页、CPU 利用率下降,这就是抖动(颠簸)。若系统因 CPU 空闲而继续增加进程,可能进一步减少每个进程的可用页框,加重抖动。控制方法包括局部置换、按工作集或缺页率调整页框、挂起部分进程释放内存,以及增加物理内存。

12 伙伴系统(6.1–6.3,领会)

用户进程的页面可以离散映射,但内核申请某些缓冲区等结构时可能需要连续的物理页框。Linux 等内核使用伙伴系统(Buddy System)管理空闲空间,将 \(2^k\) 个连续页框组成的块称为 \(k\) 阶块,按阶分别维护空闲链表。

申请 \(n\) 个页框时,先向上取整到可容纳它的最小 \(2^k\)。若 \(k\) 阶链表有空闲块,直接分配;否则从 \(k+1\) 阶或更高阶取得空闲块,逐级对半拆分为 \(k\) 阶块。分配其中一块,另一块加入 \(k\) 阶空闲链表。

自编例:初始有一块 16 页框空闲区,现申请 3 页框,需分配 \(2^2 = 4\) 页框。先将 16 拆为 8 + 8,再将其中一个 8 拆为 4 + 4。分配一个 4,其中 1 页框形成内部碎片;剩余一个 4 和一个 8 分别加入对应阶的空闲链表。

释放时,只有由同一 \(2^{k+1}\) 上级块拆出的两个空闲伙伴块才能合并,大小相同且相邻还不够。设块大小为 \(b=2^k\),对齐的起始页框号为 \(x\),伙伴起址为 x XOR b。

例如,[0, 4) 和 [4, 8) 的起址满足 \(0\oplus4=4\),因此可合并为 [0, 8)。[4, 8) 与 [8, 12) 虽然相邻,但分别属于 [0, 8) 和 [8, 16) 两个上级块;\(4\oplus4=0\),不等于 8,不能合并。教材中的阶数上限、页大小和 Linux 结构定义属于特定版本实例;本节重点是拆分规则和用异或判断伙伴块。

13 考核要求

本章大纲分 6 组。识记包括存储层次与局部性(1.1–1.2)、连续分配与固定分区(3.1–3.2)、分页概念(4.1)、虚拟存储定义(5.1)、页框分配策略(5.3–5.4)和抖动(5.7)。领会包括链接装入与重定位(2.1–2.3)、TLB(4.3)、分段与段页式(4.5–4.6)、缺页中断处理(5.2)、页面置换与 EAT 计算(5.5–5.6),以及伙伴系统(6.1–6.3)。

简单应用和综合应用涉及三类计算:动态分区的分配与回收(3.3)、基本分页地址映射(4.2)和两级页表地址映射(4.4)。练习时应能画表并完成十六进制地址切分。

14 教材本章习题

题目取自教材第 4 章“思考题与练习题”(共 16 题),答案取自教材附录“部分习题参考答案”(全部收录)。

14.1 单项选择题

1. 关于操作系统内存管理的功能,下列叙述错误的是【 】。

  • A. 回收内存

  • B. 为进程分配内存

  • C. 使程序尽可能用物理地址访问内存

  • D. 与硬件协同完成逻辑地址到物理地址的转换

答案与解析

参考答案: C。内存管理的作用之一是让程序使用逻辑地址(虚拟地址)访问内存。逻辑地址到物理地址的转换由软硬件协同完成,物理地址并不直接暴露给程序。

2. 在基于分页的虚拟存储管理系统中,页表项增加了修改位字段,下列程序中,需要使用这个字段的是【 】。

  • A. 分配页框的程序

  • B. 选择换出页的程序

  • C. 从外存调入页的程序

  • D. 访问页的程序

答案与解析

参考答案: B。修改位标记该页调入后是否被写过。选择换出页时据此判断是否必须先写回外存;未被修改的页可直接丢弃。

3. 多道程序环境下,操作系统分配 CPU 资源的基本单位是【 】。

  • A. 程序

  • B. 进程

  • C. 作业

  • D. 指令

答案与解析

参考答案: B。多道程序环境中进程是资源分配与独立运行的基本单位;作业是面向用户的提交单位,程序是静态的。

4. 采用二级分页的存储管理系统中,若分页逻辑地址用 32 位表示,其中高 10 位表示页目录号 p1,中间 10 位表示页号 p2,低 12 位表示页内偏移,则一个进程的逻辑地址空间大小最大为【 】。

  • A. 4 GB

  • B. 2 GB

  • C. 4 MB

  • D. 4 KB

答案与解析

参考答案: A。逻辑地址共 32 位,无论怎样划分为 p1、p2、d,可寻址空间都是 2³²=4 GB。不要误按页内偏移 12 位答成 4 KB。

5. 在一个实际系统中,进行页置换时,通常选择换出的页是【 】。

  • A. 经常不用的页

  • B. 不会被修改的页

  • C. 最近既没有被修改也没有被访问过的页

  • D. 将来最久不会被访问的页面

答案与解析

参考答案: C。D 是理论最优(OPT)的判据,实际系统无法预知将来。实际做法综合访问位与修改位,优先淘汰近期既未访问又未修改的页,同时避免写回开销。

14.2 填空题

6. 连续内存管理方式有 3 种,即___、___和___。

答案与解析

参考答案: 单一连续区分配;固定分区分配;动态分区分配。

7. CPU 的页表寄存器用于存放 ___ 进程的页表起始地址。

答案与解析

参考答案: 当前。

8. LRU 置换算法选择的换出页是 ___ 的页。

答案与解析

参考答案: 最近最久未访问。

9. 快表中存放的内容是___。

答案与解析

参考答案: 最近被访问过的页表项。

10. 在分段存储管理系统中,段表项中包含的基本内容有 ___ 和 ___。

答案与解析

参考答案: 段基址;段大小。教材附录另列出“段号”,但段号用于索引段表,本身不作为段表项的基本内容保存。

11. 虚拟存储管理系统的特征有多次性、___、___和___。

答案与解析

参考答案: 离散性;对换性;虚拟性。

14.3 简答题

12. 静态链接程序完成什么功能?

答案与解析

参考答案: 把若干目标模块组合成一个完整的装入模块,同时处理模块组合引起的相对地址变化和外部符号引用。前一项工作是重定位,后一项是符号解析。

13. 请说明分页存储管理的基本原理。

答案与解析

参考答案: 把逻辑地址空间划分为大小相等的页,把物理内存划分为同样大小的页框。页可以离散地放入任意页框,系统用页表把页号转换为页框号。页内偏移保持不变,与页框号拼接成物理地址,从而避免连续分配的外部碎片。

14. 什么是抖动?抖动产生的原因是什么?

答案与解析

参考答案: 抖动是进程频繁换页、用于换页的时间超过有效执行时间的状态。原因通常是分配给进程的页框数不足以容纳其当前工作集,使刚换出的页很快又被访问。可通过减少并发度、调整页框分配或增加内存缓解。

15. 请说明分段存储管理的原理。

答案与解析

参考答案: 按程序的逻辑单位(如代码段、数据段、栈段)划分地址空间,每段长度可变。系统先以段号查段表,读取段基址和段长,检查段内偏移是否越界;合法时以段基址加偏移得到物理地址。分段便于共享与保护,但会产生外部碎片。

14.4 综合应用

16. 初始空闲链中第一个空闲区起址 20 KB、大小 10 KB;第二个起址 50 KB、大小 100 KB;第三个起址 300 KB、大小 10 KB。分别画出释放条件(1)(2)(3)后的空闲链(教材图 4-57 至图 4-60)。

答案与解析

参考答案: 三种情形的结果见教材附录图 A-1a 至 A-1c。作答时先读出各图中被释放区的起址与长度,再按第 3.2 节判断能否合并。与前一空闲区末址相接,就并入前者;与后一空闲区首址相接,就并入后者;两侧都相接,三者合并为一块;都不相接,则作为新空闲区按地址插入链中。三个释放条件的具体数值以原图为准。第 3.2 节另给出文字数据完整的合并例。

15 闭卷复习与跨章联系(补充)

一、闭卷自答(合上书逐题口述)

  1. 存储层次与局部性,为什么能让小容量高速存储支撑大程序?
  2. FF、NF、BF 各怎么选空闲区?回收时哪几种情况要合并?
  3. 逻辑地址怎么切成页号和页内偏移,物理地址怎么拼?TLB 命中率怎么进公式?
  4. 二级页表为什么可能更省?地址怎么拆、目录和页表怎么查?
  5. 反置页表按什么建、怎么查?虚拟存储四个特征与缺页处理分几步?
  6. 六种置换算法各依据什么?FIFO 的异常在哪?伙伴系统怎么拆、怎么合并?

二、本章易错

  1. 只有前一区的终点等于后一区的起点,两个区间才在物理地址上相邻(第 3.2 节)。
  2. TLB 没命中不等于缺页:缺的只是地址翻译的缓存项,页通常还在内存里(第 5 节)。
  3. 两级页表省内存的前提是地址空间稀疏;全部用满时反而多出一个页目录(第 6.1 节)。

三、本章骨架

层次 回答什么 所在节
放哪儿 连续分配、分区与页框 第 1–4 节
怎么翻 分页、分段、段页式、TLB、二级页表、反置页表 第 4–7 节
按需调页 虚拟存储、缺页、页面置换、工作集 第 8–11 节
分配物理块 伙伴系统的拆分与合并 第 12 节

四、跨章指路

  1. 拥有独立地址空间的进程实体与缺页阻塞后的三态切换,见第 2 章。
  2. 文件读写要经过本章的地址映射才能落进物理内存缓冲区(见第 5 章);而一次缺页中断到底要等多少毫秒,取决于磁盘寻道调度与缓冲管理(见第 6 章)。
  3. 见《计算机组成原理》第 5 章:那边讲 MMU、TLB 与 CPU Cache 协同工作的硬件通路;这边讲页框分配、页面置换策略与进程隔离。