操作系统 · 2027 考研计算机 408

第 3 章 内存管理(连续分配 · 分页分段 · 虚拟内存)

目标院校:四川大学 / 电子科技大学 | 建议用时:概念 4 小时 + 例题练习 5 小时

本章地位:内存管理是 408 操作系统部分分值最重、计算题最密集的一章:地址翻译(给逻辑地址算物理地址)、页表 / 多级页表大小、TLB 有效访问时间、页面置换缺页次数,都是可以精确到「代数值验证」的硬计算;同时碎片、重定位、抖动等概念辨析几乎每年都有选择题。主线只有一条:程序怎么装进内存 → 怎么把逻辑地址变成物理地址 → 内存不够用时怎么办。抓住这条主线,十几种零散概念就都挂得上钩。

考点常考题型热度本章位置
重定位(静态 / 动态)与内存保护选择题★★★3.1
动态分区四种分配算法、碎片辨析选择 / 大题★★★★3.2
分页地址翻译、页表与多级页表大小大题(几乎必考)★★★★★3.3
快表 TLB 与有效访问时间 EAT计算题★★★★3.3
分段越界判断、分页 vs 分段、段页式选择题★★★3.4
缺页中断流程与性能计算选择 / 计算★★★★3.5
页面置换算法(含 Belady 异常、改进 CLOCK)大题(几乎必考)★★★★★3.5
页面分配策略、抖动与工作集选择题★★★3.5

3.1 内存管理概念与程序装入

内存管理的四大功能
  1. 内存空间的分配与回收:操作系统记录哪些内存空闲(数据结构:空闲分区表 / 空闲分区链 / 位图 / 页框链),按需分配给进程,回收时合并相邻空闲区;
  2. 地址转换(重定位):把程序中的逻辑地址翻译成物理地址;
  3. 内存保护:保证各进程在自己的地址空间内运行,互不越界干扰;
  4. 内存扩充:借助覆盖、交换、虚拟存储技术,让「小内存」跑「大程序」。

3.1.1 逻辑地址与物理地址

定义逻辑地址(相对地址):用户程序经编译链接后目标模块中使用的地址,每个进程都从 0 开始编址,互相独立,又称虚拟地址;物理地址(绝对地址):内存单元的真实编号,CPU 执行时最终按物理地址访存。程序装入内存时必须把逻辑地址转换为物理地址,这一过程称为地址重定位(地址变换)。
易错① 逻辑地址空间大小由机器的地址结构(地址位数)决定,与实际内存大小无关:32 位地址结构的逻辑地址空间固定为 \(2^{32}\,\mathrm{B}=4\,\mathrm{GB}\),哪怕物理内存只有 512MB;
② 「从 0 开始编址」意味着题目给十进制逻辑地址时,页号 = 地址 ÷ 页大小(取整),页内偏移 = 余数——先拆后查,顺序不能反(见 3.3)。

3.1.2 三种装入方式与重定位

源程序要经过编译(.obj)→ 链接(.exe,形成完整逻辑地址空间)→ 装入(映射到物理内存)三步才能运行。按「什么时候做地址转换」分三种装入方式:

装入方式何时重定位程序能否移动适用场景
绝对装入编译时(程序中直接写死物理地址)不能单道环境,编译时已知程序将放到何处
可重定位装入(静态重定位)装入时一次性全部转换装入后不能再移动早期多道批处理,需连续分配一整块
动态运行时装入(动态重定位)运行时逐条转换(借助重定位寄存器)可以移动,还可请求调入更多内容现代 OS,是虚拟内存的前提
动态重定位程序装入后所有地址仍保持逻辑地址,真正执行到某条指令时才由硬件完成「物理地址 = 逻辑地址 + 重定位寄存器(基址寄存器)中的值」。重定位寄存器的内容由操作系统在进程切换时设置,用户进程不能直接修改。
一句话记忆静态重定位「一次定终身、终身不能动」;动态重定位「边跑边翻译、随时可以搬」。正因为能搬,动态分区才能用紧凑(3.2.4),虚拟内存才能把程序部分装入(3.5)——两处考点都靠它撑腰。
例 1 高频考点 重定位与装入方式辨析

下列关于地址重定位的叙述中,错误的是( )
A. 静态重定位在程序装入时完成地址变换,装入后程序不能在内存中移动
B. 动态重定位需要重定位寄存器的支持,程序运行期间可以在内存中移动
C. 采用动态重定位的系统中,进程的物理地址在装入时就已全部确定
D. 动态重定位是实现虚拟存储器的基础之一

查看解答

C。逐项分析:

A 对:静态重定位装入时一次改完所有地址,之后若移动,已改好的地址全部作废,所以不能再移动;

B 对:动态重定位执行时才做「逻辑地址 + 重定位寄存器」,移动程序后只需修改寄存器内容,程序代码不动;

C 错:动态重定位下物理地址在每条指令执行时才实时算出,装入时并不确定——这正是程序可移动、可部分装入的原因;

D 对:虚拟内存「先调入一部分即可运行」依赖运行中继续调入并重定位,静态重定位做不到。

练习 1

判断正误:(1) 逻辑地址就是物理地址经过编译后的另一种写法;(2) 每个进程的逻辑地址空间都从 0 开始;(3) 采用静态重定位时,进程运行中仍可申请再移动到更大的空闲区。

查看答案

(1) 错:两者是不同空间的概念,逻辑地址面向程序(相对地址),物理地址面向存储器(绝对地址),需重定位建立映射;

(2) 对:各进程逻辑地址空间独立,都从 0 编址,所以不同进程中同一个逻辑地址对应不同物理单元;

(3) 错:静态重定位装入后不能移动,想移动只能靠动态重定位。

3.1.3 内存保护的两种实现

两种硬件方案
  1. 上、下限寄存器:存放进程物理地址空间的上限与下限。访存时检查:下限 ≤ 物理地址 ≤ 上限,越界则产生越界中断(陷入异常);
  2. 重定位寄存器 + 界地址寄存器:重定位寄存器存物理起始地址(基址),界地址寄存器存逻辑地址空间长度(限长)。访存时先判 逻辑地址 < 界地址寄存器内容,合法则 物理地址 = 重定位寄存器内容 + 逻辑地址。
两种方案的寄存器都由操作系统特权指令装载,进程切换时更新;越界则中断处理,实现「内存保护」。
易错方案二中比较的是逻辑地址与界地址寄存器(先判长度再加重定位),方案一中比较的是物理地址与上下限——两者判断对象不同,选择题常拿来偷换。另外注意:实现内存保护必须有硬件支持(一对寄存器),纯软件检查不可靠。
练习 2 易错

某系统采用「重定位寄存器 + 界地址寄存器」实施保护,重定位寄存器内容为 3000,界地址寄存器内容为 500。进程访问逻辑地址 600 会发生什么?若访问逻辑地址 400,对应物理地址是多少(按字节编址)?

查看答案

逻辑地址 600 ≥ 界地址 500 → 越界,产生越界中断,不会去访存;逻辑地址 400 < 500 合法,物理地址 = 3000 + 400 = 3400。注意先判断、后相加,顺序别颠倒。

3.2 连续分配管理方式

连续分配指为一个用户程序划分一段连续的内存空间。按「分区何时划分、能否变化」分为单一连续、固定分区、动态分区三种,碎片类型各不相同——内部 / 外部碎片之辨是本节选择题的常客。

3.2.1 单一连续与固定分区分配

三种连续分配
  1. 单一连续分配:内存分系统区 + 用户区,用户区任一时刻只装一道程序。无外部碎片,有内部碎片(分给它的用不完也算它的),利用率最低;
  2. 固定分区分配:用户区预先划成若干固定大小的分区(大小可相等也可不等,不等时按常用作业规模搭配可提高利用率),每个分区装一道作业,支持多道。分区总有剩余 → 内部碎片;分区之间不会出现无法利用的小空闲 → 无外部碎片;
  3. 动态分区分配:进程装入时才按其大小「量体裁衣」建分区 → 分区内部不浪费,但进程不断进出会在分区之间留下难以利用的小空闲块 → 外部碎片。
一句话记忆「分给自己用不完的是内部碎片,散在别人之间用不上的是外部碎片」。固定分区 / 单一连续 / 分页(最后一页凑不满)→ 内部碎片;动态分区 / 分段 → 外部碎片。

3.2.2 动态分区分配与空闲分区表

数据结构动态分区用空闲分区表或空闲分区链记录每个空闲区的起始地址与大小。分配时找到一个 ≥ 请求量的空闲区,从低地址切割一块分出(剩余部分仍留在表中);回收时视邻接情况合并(见 3.2.4)。表的组织顺序(按地址递增 / 按容量递增 / 递减)直接决定算法行为,审题先看排序方式。
练习 3

固定分区分配中,各分区大小可以不相等,这样做的主要目的是什么?固定分区有外部碎片吗?

查看答案

根据常驻作业的大小配置不同分区,小作业进小分区、大作业进大分区,减少每个分区内被浪费的空间(内部碎片),提高内存利用率;固定分区的空闲空间始终整块地留在分区之外,不会被作业切割得七零八落,因此无外部碎片(浪费都算作内部碎片)。

3.2.3 四种动态分区分配算法 高频考点

算法空闲区排列规则选择策略优缺点
首次适应 First Fit按地址递增从头顺序找第 1 个够大的简单、开销小;低址部分不断被切小,但高址端保留大分区,综合性能通常最好
最佳适应 Best Fit按容量递增第 1 个够大的即最小的够大者「只求够用」每次剩下最小的碎片 → 产生大量难以利用的小外部碎片
最坏适应 Worst Fit按容量递减挑最大的分区切切剩的块仍较大尚可再用,但大分区迅速耗尽,后续大作业难以装入
邻近适应 Next Fit按地址递增(循环链)从上次查找结束处继续找第 1 个够大的分配更均匀,但大的高址分区更早被用掉,综合通常不优于首次适应
空闲分区(按地址递增) 100K 500K 200K 300K 600K ← 作业申请 212K 首次适应 → 500K 第一个够大的 最佳适应 → 300K 最小的够大者 最坏适应 → 600K 最大的分区 邻近适应(循环首次适应) 已分配 空闲 空闲 已分配 空闲 ← 指针:从上次结束处继续找 绕回表头循环,不总是从头开始
图 3-1 申请 212K 时四种算法的选择:首次适应从头顺序找(500K),最佳适应挑最小够大者(300K),最坏适应挑最大者(600K),邻近适应从上次结束位置循环往后找
易错① 最佳适应「最佳」指的是本次剩下最少,长期看碎片最多;考试若问「哪种算法通常性能最好」,答案常是首次适应;
② 邻近适应的空闲链仍按地址递增(不是按容量),只是查找起点不回表头;
③ 分配算法针对的是动态分区;固定分区不存在「选哪块更好」的问题(分区大小固定,作业进匹配的分区即可)。
例 2 真题风格 动态分区分配算法推演

某系统内存空闲分区(按地址递增)依次为 100KB、500KB、200KB、300KB、600KB。现有作业序列依次申请 212KB、117KB、526KB。分别用首次适应、最佳适应、最坏适应算法处理,各作业装入哪个分区?哪种算法最终无法满足第三个作业?

查看解答

首次适应(从头找第 1 个够大的,剩余留在原地):

212K → 500K(剩 288K);117K → 288K(剩 171K);526K → 现有 100K、171K、200K、300K、600K 中只有 600K 够 → 600K(剩 74K)。三个作业全部装入 ✓

最佳适应(每次挑最小够大者):212K → 300K(剩 88K);117K → 200K(剩 83K);526K → 600K(剩 74K)。全部装入 ✓(但留下 88K、83K 等小碎片)

最坏适应(每次挑最大者):212K → 600K(剩 388K);117K → 388K(剩 271K);526K → 现有 100K、500K、200K、300K、271K 都不够 → 分配失败。

套路总结:这类题拿空闲区列表逐步「划掉—改余量」即可;最佳适应盯着「够用的最小」,最坏适应盯着「最大」,首次适应从低址起按顺序找。三种算法分完后再检查一遍剩余容量表,防止算错。

练习 4 易错

接例 2 的初始状态,若采用邻近适应算法(初始指针在表头),三个作业分别装入哪个分区?

查看答案

212K:从表头起 → 500K(剩 288K),指针移到 500K 分区;
117K:从指针处向后找 → 288K 够(剩 171K),指针停在原 500K 分区;
526K:从指针处向后 → 200K、300K 不够,绕回 100K 也不够,到 600K 够 → 600K(剩 74K)。

对比:首次适应第三步是「从头找」,邻近适应是「从上次位置接着找」,本题结果恰好相同,但中间检查的分区不同——真题常考这个差别。

3.2.4 分区回收、碎片与紧凑

动态分区回收的四种情况回收区(大小为 R,起始地址为 A)归还时,看它与前、后相邻空闲区的邻接关系:
情况处理办法
① 仅前邻接空闲区与前邻合并:修改前邻分区大小 += R(起始地址不变)
② 仅后邻接空闲区与后邻合并:新分区起始地址 = A,大小 = R + 后邻大小(回收区地址作为新起点)
③ 前后都邻接空闲区三区合一:修改前邻大小 += R + 后邻大小,删除后邻表项(起始地址仍为前邻的)
④ 前后都不邻接新建一个表项(起始地址 A、大小 R),按地址有序插入空闲表
注意情况②③中修改的是起始地址与大小两个字段,表项数在③中减一、④中加一。
内部碎片 vs 外部碎片全表
管理方式内部碎片外部碎片
单一连续分配有(整个用户区的富余)无
固定分区分配有(分区内浪费)无
动态分区分配无(量体裁衣)有(分区之间的小空闲)
基本分页有(最后一页凑不满)无
基本分段无有(段间小空闲)
段页式有(每段最后一页的页内碎片)无
紧凑(Compaction)把内存中的进程整体搬移到地址一端,把零散外部碎片拼成一个大空闲区。代价是大量 CPU 时间,且必须以动态重定位为前提(静态重定位下程序装入后不能移动)。固定分区、分页「无外部碎片」也就不需要紧凑。
练习 5

某动态分区系统回收一个起始地址 60K、大小 30K 的分区时,空闲分区表中已有两个空闲区:起始 30K 大小 30K,起始 90K 大小 20K。本次回收属于哪种情况?回收后空闲区表变成什么样?

查看答案

回收区 [60K, 90K) 与前邻 [30K, 60K) 恰好相邻、与后邻 [90K, 110K) 也相邻 → 情况③前后都邻接:三区合一为起始 30K、大小 30 + 30 + 20 = 80K 的一个空闲区,删除原后邻表项。回收后空闲表仅剩一项:起始 30K,大小 80K(假设无其他空闲区)。

3.3 基本分页存储管理 高频考点

3.3.1 页面、页框与地址结构

基本思想把进程逻辑地址空间分成大小相等的页面(Page),把物理内存分成同样大小的页框 / 物理块(Frame);任一页面可装入任一页框,离散分配、连续逻辑相邻不再要求物理相邻。页面向页框的映射关系记录在页表中。页面大小是 2 的整数次幂(典型 4KB)。
地址结构与位数拆分逻辑地址被硬件自动拆成两部分: \[ \underbrace{P}_{\text{页号}} \ \big| \ \underbrace{W}_{\text{页内偏移}} \qquad W 的位数 = \log_2(\text{页大小}) \] 若逻辑地址 \(n\) 位、页面 \(2^{k}\,\mathrm{B}\),则页内偏移 \(k\) 位,页号 \(n-k\) 位,进程最多 \(\dfrac{2^{n}}{2^{k}}=2^{n-k}\) 页。页号位数 = ⌈log₂ 页数⌉。例如 32 位地址、4KB 页 → 偏移 12 位、页号 20 位、最多 \(2^{20}\) 页。
易错① 分页对程序员透明(地址拆分由硬件做),分段对程序员可见(3.4);
② 分页没有外部碎片(任何页框都能用),但平均每个进程浪费半页内部碎片;
③ 十进制地址先「除页大小取商余」再查页表;十六进制地址直接按位数切(4KB → 低 12 位十六进制 3 位)。
例 3 高频考点 地址翻译(页大小 4KB)

某分页系统页大小 4KB,某进程页表如下:页 0→物理块 5,页 1→块 9,页 2→块 7,页 3→块 1。求:(1) 逻辑地址 8644 的物理地址;(2) 十六进制逻辑地址 0x17A3 的物理地址。

查看解答

4KB = \(2^{12}\,\mathrm{B}\),页内偏移 12 位。4KB 页大小 → 页号 = ⌊地址 / 4096⌋,偏移 = 地址 mod 4096。

(1) \(8644 = 2\times4096 + 452\) → 页号 2、偏移 452。查表:页 2 → 块 7。物理地址 = \(7\times4096 + 452 = 28672 + 452 = \mathbf{29124}\)。

(2) 4KB 页 → 低 3 个十六进制位(12 位二进制)是偏移:0x17A3 → 页号 0x1、偏移 0x7A3。页 1 → 块 9(0x9)。物理地址按「块号拼偏移」直接写出:0x9 | 0x7A3 → 0x97A3。验证:0x17A3 = 6051 = 1×4096 + 1955(0x7A3 = 1955 ✓);0x97A3 = 9×4096 + 1955 = 36864 + 1955 = 38819 ✓。

套路总结:十六进制题不用换十进制,直接「切低位、查表、拼块号」:物理地址 = 块号按页大小补零拼接 + 原偏移。0x17A3 → 块 9 → 0x9 拼 0x7A3 → 0x97A3。

练习 6 方法

页大小改为 1KB,页表:页 0→块 3,页 1→块 6,页 2→块 9,页 3→块 11,页 4→块 8。求逻辑地址 4500 与 1023 的物理地址。

查看答案

1KB = \(2^{10}\,\mathrm{B}\):\(4500 = 4\times1024 + 404\) → 页 4 → 块 8 → \(8\times1024 + 404 = \mathbf{8196}\);

\(1023 = 0\times1024 + 1023\) → 页 0 → 块 3 → \(3\times1024 + 1023 = \mathbf{4095}\)(正好是页 0 的最后一字节)。

3.3.2 页表与地址转换全过程

页表与页表寄存器每个进程一张页表:第 \(i\) 个表项记录「页号 \(i\) → 物理块号」(页号是隐含的数组下标,不占表项空间)。系统设页表寄存器 PTBR,存放页表在内存中的始址和页表长度(表项数);进程未运行时这两项保存在 PCB 中,上 CPU 时装入 PTBR。
① CPU 产生逻辑地址 A 页号 P 页内偏移 W 例:A=8644, 4KB 页 P=2, W=452 ② P ≥ 页表长度?越界中断 页表寄存器 PTBR 页表始址 M + 页表长度 L ③ 始址 + P×表项长度 ④ 查页表 内存中的页表 页 0 → 块 5 页 1 → 块 9 页 2 → 块 7 页 3 → 块 1 (访问内存 1 次) 取到块号 B=7 块号 B = 77×4096 = 28672 偏移 W = 452偏移原样照抄 → 相加 偏移 W 直接送来 ⑤ 物理地址 29124 无快表时共访问内存 2 次:查页表 1 次 + 取数据 1 次(单级页表)
图 3-2 基本分页地址转换全过程(例 3 数据):拆分 P|W → 越界检查 → 查页表得块号 B → 物理地址 = B×页大小 + W(偏移原样照抄,绝不参与查表)
三步口诀① 拆:按页大小拆出页号和偏移;② 查:页表始址 + 页号×表项长度 → 找到表项,先比页号与页表长度防越界;③ 拼:物理地址 = 块号×页大小 + 偏移(等价于把块号的二进制拼在偏移前面)。偏移从头到尾不变。
// 基本分页地址转换(硬件 MMU 逻辑)
输入: 逻辑地址 A, 页大小 L, 页表始址 M, 页表长度 len
P = A / L;  W = A mod L;          // 拆分: 页号与页内偏移
if (P >= len)
    触发越界中断, 终止访问;       // 页号越界
B = 内存[M + P * 表项长度];       // 查页表得物理块号 (1 次访存)
物理地址 = B * L + W;             // 块号乘页大小, 偏移原样照抄
return 访问内存[物理地址];         // 再 1 次访存, 共 2 次

3.3.3 页表大小的计算

公式 \[ \text{页表项数} = \frac{\text{进程逻辑地址空间}}{\text{页面大小}},\qquad \text{页表总大小} = \text{页表项数}\times\text{每项字节数} \] 页表项至少要装下一个物理块号:内存 \(2^{m}\,\mathrm{B}\)、页 \(2^{k}\,\mathrm{B}\) → 块号 \(m-k\) 位 → 每项至少 \(\lceil (m-k)/8\rceil\) 字节。为了硬件处理方便,页表项常取整字节并使页表对齐。
例 4 高频考点 页表大小与位数拆分(32 位 / 4KB / 4B)

某 32 位系统,页面大小 4KB,页表项 4B,内存 4GB。(1) 逻辑地址如何划分?(2) 单级页表多大?(3) 若要求页表本身也按页离散存放(每页 4KB),需要几级页表?各级占多少位?

查看解答

(1) 4KB = \(2^{12}\) → 页内偏移 12 位,页号 \(32-12=\) 20 位,进程最多 \(2^{20}\) 页;

(2) 单级页表 = \(2^{20}\) 项 × 4B = 4MB——它必须连续存放才能用「始址 + 页号×4」寻址,4MB 连续内存代价很大;

(3) 一页 4KB 能放 \(4096/4 = 2^{10}\) 个表项 → 每级页表管理 10 位;20 位页号拆成 10 + 10:32 位地址 = 10 位一级页号 + 10 位二级页号 + 12 位偏移。一级页表(页目录)\(2^{10}\) 项 × 4B = 4KB,恰好一页,可整体常驻内存。

套路总结:级数 = ⌈(地址位数 − 偏移位数) / 每级管理位数⌉。位数对不上时最后一级少几位(如 40 位地址 → 10+10+8+12 三级)。

3.3.4 快表 TLB 与有效访问时间 高频考点

快表 TLB把最近用过的页表项(页号→块号)复制到高速相联存储器(按内容并行查找,不按地址)中,称为快表(TLB);内存中的完整页表相应称为慢表。依据局部性原理(3.5.1),近期访问过的页面很可能再次被访问,TLB 虽小(几十项)命中率却很高。TLB 命中只需 1 次访存;未命中需先访存查页表、再访存取数据,共 2 次(单级页表)。慢表项与快表项同时更新,TLB 属硬件对程序员透明。
CPU 发出逻辑地址 TLB 快表相联查找 20ns 命中(概率 h)→ 直接得块号 未命中(1−h)→ 查慢表 访存①:一级页表(页目录)10 位一级页号 → 二级页表始址 访存②:二级页表10 位二级页号 → 物理块号 访存③:取数据物理地址 → 数据 TLB 命中路径 跳过访存①② 单次访存 100ns,TLB 20ns TLB 命中:20 + 100 = 120ns 未命中(单级页表):20 + 2×100 = 220ns 未命中(二级页表):20 + 3×100 = 320ns 无 TLB 的二级页表:3×100 = 300ns 快表把「查页表」的访存省掉, 页表级数越多省得越多
图 3-3 TLB 与两级页表的访问路径:命中走绿色捷径(TLB + 1 次访存),未命中沿红色路径逐级查页表(TLB + 3 次访存)再取数据
例 5 真题风格 TLB 有效访问时间 EAT(两种模型)

某系统访存一次 100ns,访问 TLB 一次 20ns,单级页表,TLB 命中率 90%。分别按以下两种模型求一次访存的有效时间 EAT:
模型一:先访 TLB,未命中再访存查页表(串行);
模型二:TLB 查找与访存查页表同时启动(并行,未命中的 TLB 时间被查页表时间覆盖)。

查看解答

模型一(串行):命中 = TLB 20 + 取数据 100 = 120ns;未命中 = TLB 20 + 查页表 100 + 取数据 100 = 220ns。

\[ EAT = 0.9\times120 + 0.1\times220 = 108+22 = 130\ \mathrm{ns} \]

模型二(并行):命中仍是 20+100 = 120ns;未命中时 TLB 的 20ns 与查页表的 100ns 重叠,只计 100 + 100 = 200ns。

\[ EAT = 0.9\times120 + 0.1\times200 = 108+20 = 128\ \mathrm{ns} \]

对比:完全不用 TLB 的基本分页每次 \(2\times100=200\)ns,引入 TLB 后性能显著改善。

易错:题目不说明时按王道 / 真题习惯用模型一(TLB 时间每次都计);看到「同时访问 / 并行访问 TLB 与页表」才用模型二。二级页表 + TLB 串行公式:\(EAT = h(t_{TLB}+t_{mem}) + (1-h)(t_{TLB}+3t_{mem})\)。

练习 7

二级页表系统,访存 100ns,TLB 10ns,命中率 98%。求无 TLB 与有 TLB(串行模型)两种情况下的 EAT,并计算加速比。

查看答案

无 TLB:\(3\times100=300\)ns(页目录、页表、数据各一次);

有 TLB:\(EAT = 0.98\times(10+100)+0.02\times(10+300) = 107.8+6.2 = 114\)ns;

加速比 \(300/114\approx2.6\) 倍。可见页表级数越多,TLB 省下的访存越多。

3.3.5 两级与多级页表

为什么要分级单级页表有两个致命问题:① 32 位 / 4KB / 4B 下页表高达 4MB 且必须连续存放(「始址 + 页号×4」要求表连续);② 页表要全部调入内存才能运行,哪怕进程只用到很少几页。把页表再分页:4MB 页表拆成 1024 页(每页 4KB、1024 项),再用一张 4KB 的一级页表(页目录)登记它们——两级页表。每张二级页表可离散存放,且没用到的二级页表不必调入内存(配合虚拟内存,3.5)。
易错① 多级页表并不能减少页表总开销(反而多了页目录),它解决的是「连续存放 + 必须整体驻留」两个问题;
② 分级后访存次数增加:\(n\) 级页表无 TLB 时需 \(n+1\) 次访存(单级 2 次、二级 3 次)——靠 TLB 挽回;
③ 各级「每级管理位数」由「一页能装多少个表项」决定,不是想怎么拆就怎么拆。
练习 8 易错

某系统逻辑地址 40 位,页面 4KB,页表项 4B,要求页表分页离散存放。至少需要几级页表?画出地址划分。

查看答案

偏移 12 位 → 页号共 \(40-12=28\) 位;一页 4KB 装 \(2^{10}\) 项 → 每级管 10 位;\(\lceil 28/10\rceil = 3\) 级。

划分:10 位一级 + 10 位二级 + 8 位三级 + 12 位偏移(最后一级只管 \(28-20=8\) 位,页目录仅 \(2^{8}=256\) 项 = 1KB)。

无 TLB 访存 \(3+1=4\) 次。注意级数向上取整、末级位数可以不满 10 位。

3.4 基本分段与段页式管理

3.4.1 分段:二维地址空间

基本思想按程序的逻辑结构划分成若干段(主程序段、子程序段、数据段、栈段……),每段内部连续、段长可变,段与段之间可离散存放。逻辑地址是二维的:\((\text{段号 } S,\ \text{段内偏移 } W)\)。每个进程一张段表:表项含段长 C 与基址 B(这两个字段都必须有)。
地址转换(越界判断是重点)
  1. 段号 \(S\) 与段表长度比较:\(S\ge\) 段表长度 → 段号越界,中断;
  2. 段表始址 + \(S\times\)表项长度 → 取出该段的段长 C 与基址 B;
  3. 段内偏移 \(W\ge C\) → 段内越界,中断(分段特有!分页的页内偏移不可能越界——地址拆分方式保证偏移恒小于页大小);
  4. 物理地址 = \(B + W\)。整个过程访存 2 次(段表 1 次 + 数据 1 次)。
例 6 高频考点 分段越界判断与地址计算

某进程段表如下(按字节编址):

段号段长基址
015KB100KB
130KB130KB
220KB180KB
310KB220KB

判断下列逻辑地址是否越界,越界的指出原因,合法的算出物理地址:(a) (2, 15K);(b) (3, 12K);(c) (0, 8K);(d) (4, 1K)。

查看解答

(a) 段号 2 < 4 ✓,偏移 15K < 段长 20K ✓ → 合法,物理地址 = 180K + 15K = 195KB;

(b) 段号 3 < 4 ✓,但偏移 12K ≥ 段长 10K → 段内越界中断;

(c) 段号 0 ✓,8K < 15K ✓ → 100K + 8K = 108KB;

(d) 段号 4 ≥ 段表长度 4 → 段号越界中断(段表只有 0~3 段)。

易错:分页只判一次越界(页号 ≥ 页表长度),分段要判两次(段号、段内偏移各一次)。若题目给十进制一维地址,先按「段号位数 + 偏移位数」拆成二维再判断。

3.4.2 分页 vs 分段对比 高频考点

对比维度分页分段
划分依据物理划分:按固定页大小机械切分逻辑划分:按程序模块(代码 / 数据 / 栈)
地址空间一维:一个线性地址即可确定(页号隐含在地址高位)二维:必须 (段号, 段内偏移) 两个分量
大小页大小固定,由硬件决定段长可变,由程序逻辑决定
对程序员透明(不可见)可见(需要程序员 / 编译器划分段)
碎片内部碎片(最后一页凑不满),无外部碎片外部碎片(段间小空闲),无内部碎片
共享与保护不易实现(页是机械切块,不对应完整模块)便于共享和保护(以段为单位共享,如共享代码段;需可重入码)
越界判断一次(页号 vs 页表长度)两次(段号 vs 段表长度、偏移 vs 段长)
记忆钩子「页是物理的、透明的、一维的、内部碎片;段是逻辑的、可见的、二维的、外部碎片、好共享」。可共享的是代码段(纯代码 / 可重入码),数据段一般不共享。

3.4.3 段页式管理

先分段、后分页先把程序按逻辑分段,每段内再分页;内存仍按页框离散分配。逻辑地址结构为三段:段号 S + 段内页号 P + 页内偏移 W。每进程一张段表,每个段一张页表(段表项存该段页表的始址与页表长度,不再存段长基址)。
地址转换(3 次访存)
  1. 段号 S 查段表(访存①)→ 得到该段页表始址;
  2. 页号 P 查该段页表(访存②)→ 得到物理块号 B;
  3. 物理地址 = B×页大小 + W,取数据(访存③)。
无快表时共 3 次访存;有 TLB 命中时 1 次访存。兼具「分段好共享保护 + 分页无外部碎片」的优点,代价是地址变换更复杂、表更多。
练习 9

段页式存储管理中,逻辑地址结构为「6 位段号 + 10 位页号 + 12 位页内偏移」。(1) 该系统逻辑地址共多少位?进程最多多少段?(2) 无快表时访问一个数据需几次访存?(3) 段页式有无外部碎片?

查看答案

(1) \(6+10+12=28\) 位;段数 \(2^{6}=64\) 段,每段最多 \(2^{10}\) 页,页大小 \(2^{12}\,\mathrm{B}=4\mathrm{KB}\);

(2) 段表、页表、数据各访存一次,共 3 次;

(3) 无外部碎片(内存按页框分配),但每段最后一页可能有内部碎片。

3.5 虚拟内存与请求分页 高频考点

3.5.1 局部性原理与虚拟内存

局部性原理
  1. 时间局部性:刚被执行 / 访问过的指令 / 数据很快会再次被访问(循环、反复调用的函数、累加变量);
  2. 空间局部性:刚被访问的存储单元附近的内容很快会被访问(顺序执行、数组顺序扫描)。
传统存储管理(连续 + 基本分页分段)有两大特征:一次性(作业必须一次全部装入才能运行)与驻留性(装入后一直驻留内存到结束)。局部性原理说明这两点都浪费——任何时刻程序真正用到的只是很小一部分。
虚拟内存基于局部性原理,程序部分装入即可启动,运行中缺哪调哪(请求调页 / 调段),暂不用的换出(页面置换)。三大特征:多次性(多次调入)、对换性(换入换出)、虚拟性(容量 = 内存 + 外存之和)。实现依赖:局部性原理 + 动态重定位(3.1.2)+ 请求分页 / 请求分段技术。虚拟地址空间上限取「内存 + 外存容量」与「地址结构决定的最大空间」的较小者:32 位系统最多 4GB,与磁盘多大无关。

3.5.2 请求分页与缺页中断

请求分页页表项的扩展在基本分页页表项基础上增加四个字段:
字段含义用途
物理块号页在内存的位置地址转换
状态位(有效位)该页是否已调入内存为 0 触发缺页中断
访问位最近是否被访问过供置换算法参考(CLOCK / LRU 近似)
修改位调入后是否被修改过淘汰时为 1 才写回外存,减少 I/O
外存地址该页在外存(对换区 / 文件区)的位置缺页时调入
缺页中断要访问的页不在内存(状态位 0)时,硬件产生缺页中断。三个必考性质:
  1. 属于内中断(异常)中的「故障」(fault),而非外中断(I/O 请求引起的外部事件);
  2. 在指令执行期间产生和处理(不是一条指令执行完后才检查——外中断才是「指令周期末尾」检查);
  3. 一条指令可能引发多次缺页:如 copy A, B 两个操作数各跨一页,取指令本身还可能跨页,最多可缺 4 次(指令本身 2 页 + 两个操作数各 2 页)。
① CPU 给出逻辑地址 ② 查页表:状态位 = 1? 是 → 正常转换 拼物理地址取数 否 → 缺页中断 ③ 缺页中断处理:有空闲页框? 有 → 从外存调入该页(I/O)修改页表:块号、状态位置 1 无 → 执行页面置换算法选淘汰页 ④ 修改位 = 1?是 → 写回外存,否则跳过 ⑤ 腾出页框,从外存调入新页 转入调页 ⑥ 更新页表与快表 → 重新执行被中断的指令 (不是从下一条指令继续!被中断的指令还没做完) 缺页处理期间进程阻塞, 由 I/O 完成后再唤醒调度
图 3-4 请求分页缺页中断处理流程:查页表发现不在内存 → 有空闲页框直接调入;无空闲则先按置换算法淘汰(修改位为 1 须写回)→ 调入后更新页表,重新执行被中断的指令
// 请求分页缺页中断处理(图 3-4 对应伪码)
trap 缺页中断(页号 P):
    if (页表[P].状态位 == 1)  return;        // 在内存, 正常访问
    阻塞当前进程, 转缺页中断处理程序;
    if (无空闲页框) {
        V = 页面置换算法选淘汰页();           // OPT/FIFO/LRU/CLOCK
        if (页表[V].修改位 == 1)
            写回外存[页表[V].外存地址];       // 脏页必须写回
        回收 V 的页框; 置 页表[V].有效 = 0;
    }
    从外存[页表[P].外存地址] 调入页 P;        // I/O, 耗时毫秒级
    更新页表[P]: 块号 = 页框号, 状态位 = 1, 访问位 = 1;
    唤醒进程, 重新执行被中断的指令;           // 注意: 不是下一条
缺页率与有效访问时间设缺页率为 \(p\),一次访存 \(t\),缺页处理(含 I/O)时间 \(T\): \[ EAT=(1-p)\cdot t+p\cdot T \] 若题目还给了 TLB / 多级页表,先把「不缺页时的访存代价」按 3.3.4 的公式算好,再作为 \(t\) 代入。
例 7 真题风格 缺页率与 EAT 计算

某请求分页系统,一次访存 100ns,一次缺页处理平均 8ms(含全部 I/O 与调度开销),当前缺页率 \(p=10^{-3}\)。(1) 求 EAT;(2) 若要求缺页带来的平均开销不超过 10%(即 EAT ≤ 110ns),缺页率最高是多少?

查看解答

(1) \(8\,\mathrm{ms}=8\times10^{6}\,\mathrm{ns}\):

\[ EAT=(1-10^{-3})\times100+10^{-3}\times8\times10^{6}=99.9+8000=8099.9\ \mathrm{ns}\approx8.1\,\mu\mathrm{s} \]

(2) \(100+p\,(8\times10^{6}-100)\le110 \Rightarrow p\le\dfrac{10}{7\,999\,900}\approx1.25\times10^{-6}\),即平均每 80 万次访存至多缺页 1 次。

易错:缺页率仅 0.1%,EAT 就暴涨 80 倍——磁盘 I/O 比访存慢 5 个数量级,这就是「抖动」致命的原因(3.5.4)。单位先统一成 ns 再算。

3.5.3 页面置换算法 高频考点

缺页而无空闲页框时,必须淘汰一页。算法评价标准是缺页次数(缺页率)。注意:「缺页次数」= 装入次数 + 置换次数,页面已在内存的访问不算缺页;做题时把引用串逐个过一遍,命中打勾、缺页打叉。

1. 最佳置换算法 OPT(理论 benchmark)

OPT淘汰以后永远不会用到,或在最远的将来才会被用到的页。缺页率最低,但需要预知未来,无法实现,只用来评价其他算法的优劣(真题常问「哪个算法缺页率最低」——答 OPT)。

2. 先进先出 FIFO 与 Belady 异常

FIFO按调入先后排成队列,淘汰最早进入内存的页。实现最简单(一个队列指针),但「先来」与「常用」毫无关系,性能差;更致命的是存在 Belady 异常:分配的物理块增多,缺页次数反而可能增多。
例 8 易错 Belady 异常:3 帧 vs 4 帧全表推演

引用串 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5。用 FIFO 分别在 3 个、4 个页框下推演,统计缺页次数。

查看解答

3 帧(× 为缺页,每步框内为当前页面,加粗为新调入):

访问123412512345
框1111444555555
框222211111333
框33332222244
缺页×××××××××

共 9 次缺页(末尾访问 5 时 5 已在内存,命中)。

4 帧:

访问123412512345
框1111111555544
框222222211115
框33333332222
框4444444333
缺页××××××××××

共 10 次缺页——页框从 3 增到 4,缺页反而 9 → 10,这就是 Belady 异常。根源:FIFO 不是栈式算法(\(k\) 帧时的页集合并非 \(k+1\) 帧时的子集);LRU 与 OPT 是栈式算法,不会出现异常。

套路总结:FIFO 推演必须记「进入顺序」(队头最老),不能只看表格当前摆放;被淘汰的是最早进入的那页,哪怕它最近刚被用过。

3. LRU 最近最久未使用

LRU淘汰最近最长时间没有被访问的页(「向前看」最近的历史,OPT 是「向后看」未来,二者互为镜像)。性能接近 OPT,但硬件开销大:需要计时器 / 时间戳字段(每页配一个,每次访问都更新,选值最小的淘汰)或栈(寄存器栈)(每访问一页把它移到栈顶,淘汰栈底)——这两种实现代价都很大,实际常用它的近似算法 CLOCK。LRU 是栈式算法,无 Belady 异常。
引用串前 8 步:7, 0, 1, 2, 0, 3, 0, 4(3 个页框) 70120304 FIFO 7 0 1 2 7 3 0 4 淘汰顺序 7→0→1(按进入先后) LRU 7 0 1 2 1 3 2 4 淘汰顺序 7→1→2(按最近使用时间) 第 5 步访问 0 命中,0 变「最新」 同样 3 步缺页,但淘汰对象不同:FIFO 只看「谁先来」(第 7 步淘汰的是刚用过的 0 的邻居 1), LRU 看「谁最久没被用」(第 5 步 0 命中后续命概率大,第 7 步淘汰的是最久未用的 2)。 完整 20 步串对比见例 9:FIFO 15 次、LRU 12 次、OPT 9 次缺页。
图 3-5 FIFO vs LRU(同一引用串、3 个页框,前 8 步):黄框为新调入页,灰字为被淘汰页。FIFO 淘汰「最早进入」的 7、0、1;LRU 淘汰「最久未用」的 7、1、2
例 9 真题风格 OPT / FIFO / LRU 缺页次数对比(20 步大题)

引用串 7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1,分配 3 个页框,页框初始为空。分别用 OPT、FIFO、LRU 算法求缺页次数与命中率。

查看解答

逐位推演(框内从左到右按各算法自身顺序排列;× = 缺页,○ = 命中):

访问FIFO 框内缺页LRU 框内(右端最新)缺页OPT 框内缺页
77×7×7×
07,0×7,0×7,0×
17,0,1×7,0,1×7,0,1×
22,0,1×0,1,2×2,0,1×
02,0,1○1,2,0○2,0,1○
32,3,1×2,0,3×2,0,3×
02,3,0×2,3,0○2,0,3○
44,3,0×3,0,4×2,4,3×
24,2,0×0,4,2×2,4,3○
34,2,3×4,2,3×2,4,3○
00,2,3×2,3,0×2,0,3×
30,2,3○2,0,3○2,0,3○
20,2,3○0,3,2○2,0,3○
10,1,3×3,2,1×2,0,1×
20,1,2×3,1,2○2,0,1○
00,1,2○1,2,0×2,0,1○
10,1,2○2,0,1○2,0,1○
77,1,2×0,1,7×7,0,1×
07,0,2×1,7,0○7,0,1○
17,0,1×7,0,1○7,0,1○

统计:FIFO 缺页 15 次(命中率 5/20 = 25%),LRU 缺页 12 次(8/20 = 40%),OPT 缺页 9 次(11/20 = 55%)。

关键分歧点回放:第 4 步访问 2 时 FIFO 淘汰最早进入的 7,LRU 也淘汰 7(7 是最久未用),OPT 同样淘汰 7(7 在未来第 18 步才再现,最远);第 7 步访问 0 时 FIFO 因第 6 步刚把 0 换出而再次缺页,LRU 则命中——FIFO 的「无视访问历史」正是它缺页多的根源。

结论:OPT 9 < LRU 12 < FIFO 15,OPT 不可实现仅作基准;LRU 利用历史近似 OPT,性能最好但硬件贵;FIFO 最简单但可能 Belady 异常。

易错:① 前 3 次冷启动不算「置换」但算「缺页」;② LRU 命中时也要更新顺序,漏更新后面全错;③ 别用「看起来快满」直觉代替逐位推演——大题必须列表。

4. CLOCK 算法(简单时钟 / NRU 近似)

简单 CLOCK把页框组成循环队列,每页配一个访问位 A(访问过置 1)。需要淘汰时从指针处扫描:访问位 1 → 置 0 继续;访问位 0 → 淘汰该页,指针前移。由于扫描时会把 1 逐个清 0,第二轮必能找到 A=0 的页,最坏扫两圈。被淘汰页若修改位为 1 仍需写回外存——简单 CLOCK 没有考虑这一点。

5. 改进型 CLOCK(访问位 A + 修改位 M)

改进 CLOCK优先淘汰「既没访问过也没修改过」的页,减少写回磁盘的 I/O。按 (A, M) 组合从优到劣分四类,最多四轮必选出:
  1. 第 1 轮:找 (0, 0)——最好:最近没用过、也没改过,直接覆盖不用写回;扫描中不修改标志位;
  2. 第 2 轮:找 (0, 1)——最近没用过但被修改过,淘汰前须写回外存;找到即选;扫描中把扫过页的 A 置 0;
  3. 第 3 轮:重复第 1 轮(此时所有 A 已被清 0,等价于找 M=0);
  4. 第 4 轮:重复第 2 轮(找 M=1)。
代价是轮数增多、指针扫多圈;收益是优先免写回,I/O 大大减少。
例 10 方法 改进 CLOCK 逐轮推演

某时刻 4 个页框中页面状态如下(A = 访问位,M = 修改位),指针指向页框 1。现需淘汰一页装入新页,用改进 CLOCK 给出推演过程。

页框页面访问位 A修改位 M
1P101
2P210
3P311
4P401
查看解答

第 1 轮(找 (0,0),不改标志):框1 (0,1) 不是 → 框2 (1,0) 不是 → 框3 (1,1) 不是 → 框4 (0,1) 不是 → 一圈没有 (0,0)。

第 2 轮(找 (0,1),扫过的页 A 置 0):回到框1,(0,1) 命中 → 淘汰 P1。因 M=1,淘汰前须把 P1 写回外存;新页装入框 1,置 (A,M)=(1,0),指针前移到框 2。

注:若第 2 轮也扫完一圈无果(说明全是 (1,x)),则第 2 轮结束时所有 A 已被清 0,第 3 轮从指针处再找 (0,0) 必然命中;再不行第 4 轮找 (0,1) 也必然命中——四轮之内必选出。

套路总结:先数一圈有没有 (0,0);没有就带着「A 置 0」再扫一圈找 (0,1)。推演题把每轮每框的 (A,M) 列成表,边扫边改,防止跳步。

练习 10 易错

引用串 4,3,2,1,4,3,5,4,3,2,1,5,3 个页框,初始为空。(1) 分别求 LRU 与 FIFO 的缺页次数;(2) 本题说明什么?

查看答案

(1) 逐位推演可得:LRU 缺页 10 次,FIFO 缺页 9 次(本串下 FIFO 反而更少)。

LRU 简推:前 3 次缺页装入 4,3,2;访问 1 缺、淘汰 4 → 访问 4 缺、淘汰 3 → 访问 3 缺、淘汰 2 → 访问 5 缺、淘汰 1 → 4 命中、3 命中 → 访问 2 缺、淘汰 5 → 访问 1 缺、淘汰 4 → 访问 5 缺、淘汰 3,共 10 次;FIFO 因淘汰顺序不同恰好少一次。

(2) 说明 LRU 不一定总比 FIFO 好——LRU 基于局部性假设,对特定访问串(局部性差的串)可能吃亏;但统计意义(多数程序)上 LRU 优于 FIFO,且 LRU 无 Belady 异常。

3.5.4 页面分配策略、抖动与工作集

驻留集与分配策略操作系统给进程分配的物理页框集合称为驻留集。两个正交维度:
维度方案含义
分配多少(驻留集大小)固定分配运行前定死页框数,不再变(难以准确估准)
可变分配运行中按缺页情况动态增减页框
置换范围局部置换只能淘汰自己的页,缺页率只取决于自己
全局置换可淘汰任意进程的页,会「抢别人内存」,被抢进程缺页率受他人影响
可行组合:固定分配 + 局部置换、可变分配 + 局部置换(据缺页频率增减自己的页框)、可变分配 + 全局置换(最常用;缺页时先取全局空闲页框,不足再按算法挑)。固定分配 + 全局置换不合理:全局置换必然改变自己(和他人)的驻留集大小,「固定」无从谈起。
调页时机与调页来源
  1. 预调页:运行前预测性地把可能用到的页一次调入(主要用于首次启动,猜测失败则白调);请求调页:运行中缺哪调哪(虚拟内存的常规方式,I/O 次数少但单次延迟高);
  2. 从何处调页:对换区(快,但外存对换空间有限);文件区(慢;没被修改过的页不必写回,淘汰后需要时直接从文件区重读);UNIX 折中:首次从文件区调入、换出时写对换区,之后都走对换区。
抖动(Thrashing)与工作集
  1. 抖动:刚被换出的页很快又要访问,缺页率急剧上升,进程把时间耗在「换出 / 调入」的 I/O 上,CPU 利用率骤降。根本原因:驻留集太小,装不下进程的工作集(多道程序度太高、分给每个进程的页框太少也会引发)。危险的正反馈:CPU 利用率低 → 调度器以为 CPU 空闲 → 继续增加进程 → 每个进程分到的页框更少 → 缺页更多 → 利用率更低。对策:降低多道程序度、按工作集给足页框;
  2. 工作集 \(W(t,\Delta)\):在某时刻 \(t\) 之前的 \(\Delta\) 个访问中实际访问过的不同页面集合,\(\Delta\) 称工作集窗口。工作集是「近期活跃页」的估计:驻留集 ⊇ 工作集时缺页率很低;若内存装不下所有进程的工作集总和,就应挂起(换出)部分进程,防抖动。
易错① 抖动时 CPU 利用率下降,但系统「很忙」——忙的是磁盘 I/O,不是计算;
② 「全局置换」不等于「可变分配」:前者说能淘汰谁的页,后者说自己页框数变不变;
③ 工作集大小 ≤ 窗口 \(\Delta\)(不同页才计数);增大 \(\Delta\) 工作集一般变大。

3.5.5 请求分段与请求段页式(简述)

请求分段虚拟内存思想同样可用于分段:段表中增加状态位、访问位、修改位、外存地址;访问的段不在内存时产生缺段中断,由 OS 调入(内存不足时需段置换,可能伴随「紧凑」)。请求分段支持段的动态增长(栈段长可扩)与段级共享,但管理开销大、有外部碎片。请求段页式则先请求调段对应的页(缺页中断逐页处理),兼具两者特点、实现最复杂。
练习 11

简答:(1) 为什么「固定分配 + 全局置换」不合理?(2) 某进程缺页率突然飙升、CPU 利用率骤降,最可能的原因是什么?给出两条对策。

查看答案

(1) 全局置换允许淘汰其他进程的页框,等于动态改变各进程的驻留集大小,与「固定分配」自相矛盾;

(2) 最可能是抖动:驻留集装不下工作集,或系统多道程序度过高。对策:降低多道程序度(挂起 / 换出部分进程);按工作集模型给缺页频繁的进程增加页框(可变分配 + 局部置换)。

3.6 章末自测 真题风格

限时 60 分钟,先做后看答案。难度:★★ 基础 / ★★★ 强化 / ★★★★ 冲刺。所有计算题答案均可用具体数值代入复核。

自测 1(选择 · ★★)

采用动态重定位的系统中,进程在内存中移动位置后,为使其继续正确运行,操作系统必须( )
A. 修改进程的所有逻辑地址 B. 修改重定位寄存器的内容 C. 重新编译链接该进程 D. 修改页表长度

查看答案

B。动态重定位下程序体内保持逻辑地址不变,物理地址 = 逻辑地址 + 重定位寄存器,移动后只需改寄存器(进程上 CPU 时由 OS 设置)。修改所有逻辑地址是静态重定位的做法且移动后已不可行。

自测 2(选择 · ★★★)

关于动态分区分配算法,下列说法错误的是( )
A. 首次适应算法的空闲分区链按地址递增排列 B. 最佳适应算法容易产生大量小的外部碎片 C. 最坏适应算法下大分区消耗快,不利于后续大作业 D. 邻近适应算法总能使缺页率最低

查看答案

D。邻近适应只是让查找起点循环前进、分配更均匀,与缺页率(页面置换概念)毫无关系,且综合性能通常不优于首次适应。A、B、C 均为正确表述。

自测 3(选择 · ★★★ 高频考点)

某分页系统页大小 2KB,页表:页 0→块 2,页 1→块 4,页 2→块 6,页 3→块 8。逻辑地址 5418 的物理地址是( )
A. 10262 B. 13610 C. 12288 D. 11466

查看答案

B。2KB = 2048B:\(5418 = 2\times2048 + 1322\) → 页 2、偏移 1322;块 6 → \(6\times2048+1322 = 12288+1322 = 13610\)。(A 是误用块 5?常见错法:先算 \(5418\div 1024\);D = \(5418 + 8\times756\) 无意义;C 漏加偏移。)

自测 4(选择 · ★★★★ 冲刺)

某 32 位系统页面大小 8KB,页表项 8B,采用单级页表时页表最大约( )
A. 4MB B. 8MB C. 16MB D. 32MB

查看答案

A。8KB = \(2^{13}\,\mathrm{B}\) → 页内偏移 13 位 → 页号 \(32-13=19\) 位 → \(2^{19}=524\,288\) 个页表项;页表 = \(524\,288\times8\,\mathrm{B}=4\,194\,304\,\mathrm{B}=4\,\mathrm{MB}\)。陷阱 C(16MB)是把页大小误当 4KB(\(2^{20}\times8\,\mathrm{B}=8\,\mathrm{MB}\) 对应 B,\(2^{21}\) 项才得 16MB);做题先写「偏移位数」,再定项数,最后乘项长。

自测 5(选择 · ★★)

二级页表、无快表的系统中,存取一个数据需要访问内存( )次;若快表命中则为( )次。
A. 2;1 B. 3;1 C. 3;2 D. 4;1

查看答案

B。二级页表:查页目录(1)+ 查二级页表(1)+ 取数据(1)= 3 次;快表命中:TLB 中直接得到块号(TLB 不算访存),只需取数据 1 次。

自测 6(选择 · ★★★)

某进程段表:段 0 长度 10KB 基址 20KB,段 1 长度 15KB 基址 40KB,段 2 长度 8KB 基址 60KB。逻辑地址 (1, 16K) 和 (2, 6K) 分别( )
A. 都合法 B. 前者段内越界,后者合法 C. 前者合法,后者越界 D. 都越界

查看答案

B。(1, 16K):段号 1 合法,但偏移 16K ≥ 段长 15K → 段内越界;(2, 6K):6K < 8K 合法,物理地址 = 60K + 6K = 66K。

自测 7(选择 · ★★★ 高频考点)

关于缺页中断,下列说法正确的是( )
A. 属于外中断,在一条指令执行结束后检测 B. 属于内中断中的故障,指令执行期间产生并处理 C. 一条指令最多产生一次缺页中断 D. 缺页中断处理后从下一条指令继续执行

查看答案

B。缺页中断属内中断(异常)中的「故障」:指令执行期间发现页不在内存立即陷入处理;一条指令可能多次缺页(操作数、指令本身都可能跨页);处理完应重新执行被中断的指令(它还没执行完),D 错。

自测 8(选择 · ★★★)

分配的物理块数(页框数)增多时,缺页次数反而可能增多的算法是( )
A. LRU B. OPT C. FIFO D. 改进 CLOCK

查看答案

C。这是 FIFO 的 Belady 异常(见例 8:3 帧 9 次 → 4 帧 10 次)。LRU 与 OPT 是栈式算法(\(k\) 帧时的页面集合是 \(k+1\) 帧时的子集),块数增多缺页次数必不增;改进 CLOCK 以 CLOCK/FIFO 思想为基础,也可能出现类似异常,但「增多反而增多」的经典指认对象是 FIFO。

自测 9(选择 · ★★)

系统出现抖动(颠簸)现象的根本原因是( )
A. 页面太大 B. 进程的驻留集小于其工作集 C. 磁盘速度太快 D. 采用了全局置换

查看答案

B。驻留集装不下工作集 → 刚换出的页马上又要用 → 缺页率飙升、CPU 都耗在 I/O 上。对策:降低多道程序度、按工作集给足页框。

自测 10(解答 · ★★★ 高频考点)

页大小 2KB,页表:页 0→块 2,页 1→块 4,页 2→块 6,页 3→块 8。求:(1) 逻辑地址 5418 的物理地址;(2) 十六进制逻辑地址 0x18A7 的物理地址。

查看解答

(1) \(5418 = 2\times2048 + 1322\) → 页 2、偏移 1322;块 6 → \(6\times2048+1322 = \mathbf{13610}\)。

(2) 2KB → 偏移 11 位,十六进制低 \(11/4\approx2.75\) 位不整——2KB 页不能按「切十六进制低位」走,先转十进制:0x18A7 = \(1\times4096+8\times256+10\times16+7 = 6311\);\(6311 = 3\times2048 + 167\) → 页 3、偏移 167;块 8 → \(8\times2048+167 = \mathbf{16551}\)。

注意与 4KB 页的差别:页大小是 2 的幂但十六进制位数不整(11 位)时,老老实实按十进制除法拆分。

自测 11(解答 · ★★★★ 冲刺)

引用串 2,3,2,1,5,2,4,5,3,2,5,2,3 个页框,初始为空。分别用 FIFO 和 LRU 推演,求缺页次数与命中率。

查看解答

FIFO(记进入队列,队头淘汰;括号内为每次访问后的页框内容,加粗为新调入):

2 [2] 缺 → 3 [2,3] 缺 → 2 命中 → 1 [2,3,1] 缺 → 5 [5,3,1] 缺(淘 2)→ 2 [5,2,1] 缺(淘 3)→ 4 [5,2,4] 缺(淘 1)→ 5 命中 → 3 [3,2,4] 缺(淘 5)→ 2 命中 → 5 [3,5,4] 缺(淘 2)→ 2 [3,5,2] 缺(淘 4)。

缺页 9 次,命中 3 次,命中率 3/12 = 25%。

LRU(括号内为栈,右端为最近使用):2 [2] 缺 → 3 [2,3] 缺 → 2 命中 → [3,2] → 1 [3,2,1] 缺 → 5 [2,1,5] 缺(淘最久未用的 3)→ 2 命中 → [1,5,2] → 4 [5,2,4] 缺(淘 1)→ 5 命中 → [2,4,5] → 3 [4,5,3] 缺(淘 2)→ 2 [5,3,2] 缺(淘 4)→ 5 命中 → [3,2,5] → 2 命中 → [3,5,2]。

缺页 7 次,命中 5 次,命中率 5/12 ≈ 41.7%。结论:本串 LRU 明显优于 FIFO——LRU 在第 3、6 步「续命」了频繁复用的 2 和 5。

结论:本串 LRU 明显优于 FIFO。

自测 12(解答 · ★★★)

二级页表系统,TLB 访问 15ns,访存 120ns,TLB 命中率 90%(串行模型,未命中时 TLB 时间照计)。求一次访存的有效访问时间 EAT。

查看解答

命中:\(15+120 = 135\)ns(TLB + 取数据 1 次访存);未命中:\(15 + 3\times120 = 375\)ns(TLB + 页目录 + 页表 + 数据)。

\[ EAT = 0.9\times135 + 0.1\times375 = 121.5+37.5 = 159\ \mathrm{ns} \]

无 TLB 时为 \(3\times120=360\)ns,TLB 使访存提速约 2.3 倍。

3.7 本章考点总结

考点常考题型热度核心方法 / 结论
重定位与内存保护选择题★★★静态一次定终身不能移动;动态靠重定位寄存器随时可搬;保护用上下限寄存器(比物理地址)或重定位 + 界地址寄存器(先比逻辑地址再加基址)
连续分配与分配算法选择 / 大题★★★★固定分区内部碎片、动态分区外部碎片;首次适应通常综合最优,最佳适应碎片最多,最坏适应耗尽大分区,邻近适应循环查找;回收四情况合并
分页地址翻译大题必考★★★★★拆(页号 = ⌊A/页大小⌋)→ 查页表 → 拼(物理 = 块号×页大小 + 偏移);4KB 页十六进制直接切低 3 位;偏移永不参与查表
页表 / 多级页表计算题★★★★页表 = (地址空间 ÷ 页大小) × 项长;32 位 4KB 页 4B 项 → 单级 4MB、拆 10+10+12 两级;多级页表解决「连续 + 全驻留」,不省总量;n 级无快表 n+1 次访存
TLB 与 EAT计算题★★★★串行:\(EAT=h(t_{TLB}+t_m)+(1-h)(t_{TLB}+kt_m)\)(k = 查页表 + 取数据的访存次数);并行:未命中不计 TLB 时间;命中恒 1 次访存
分段与段页式选择题★★★二维地址、两次越界判断、物理 = 基址 + 偏移;页物理 / 段逻辑、页透明 / 段可见、页内部碎片 / 段外部碎片、段好共享;段页式先段后页 3 次访存
缺页中断与性能选择 / 计算★★★★内中断故障、指令执行期间处理、一条指令可多次缺页、处理完重新执行本指令;\(EAT=(1-p)t+pT\),磁盘 I/O 比访存慢 5 个数量级
页面置换算法大题必考★★★★★OPT 最低但不可实现;FIFO 简单有 Belady(3 帧 9 → 4 帧 10);LRU 性能好硬件贵、栈式无异常;CLOCK 用访问位,改进型 (A,M) 四轮优先 (0,0)
分配策略与抖动选择题★★★固定 / 可变 × 局部 / 全局(固定 + 全局不成立);抖动 = 驻留集 < 工作集,CPU 利用率骤降;工作集 \(W(t,\Delta)\) 为 Δ 窗口内不同页集合
下一步本章过关标准:三道不同页大小的地址翻译 30 秒内拆完;能默写 EAT 两种模型公式与缺页率公式;OPT / FIFO / LRU / 改进 CLOCK 给串就能列表推演且不数错;碎片全表与分页 vs 分段对比表能白纸默写;能解释 Belady 异常与抖动的成因。然后进入第 4 章「文件管理」——从内存转向外存,重点变成文件物理结构与目录、磁盘调度算法。