操作系统存储管理

操作系统存储管理:从地址结构到页面置换的完整知识体系

本文系统整理页式、虚拟页式、分段、段页式、快表、页面置换、缺页计算和连续分区分配等高频考点,并集中澄清 LRU、LFU、NRU 等容易被中文名称误导的概念。

一、先建立总框架

存储管理题看似零散,实际上主要回答五个问题:

  1. 一个逻辑地址由哪些部分组成?
  2. 逻辑地址怎样转换成物理地址?
  3. 页面不在内存时,系统怎样调入和淘汰页面?
  4. 程序的访问顺序为什么会影响缺页次数?
  5. 物理内存中的空闲空间怎样分配?

对应的知识结构如下:

问题 核心知识
地址如何拆分 页号、页内偏移、段号、地址位数
地址如何转换 页表、段表、MMU、基址寄存器、快表
页面如何淘汰 OPT、FIFO、LRU、LFU、NRU、Clock
缺页次数如何计算 页框数、访问序列、数组存储顺序、局部性
空闲内存如何分配 首次、下次、最佳、最坏适应算法

做题时,第一步不是代公式,而是先确认题目问的是“页数”“页面大小”“进程总容量”“物理地址”还是“缺页次数”。


二、页式地址结构:总地址 = 页号 + 页内偏移

假设逻辑地址长度为 (n) 位,页内偏移占 (d) 位,则:

逻辑地址 = 页号(n-d位) | 页内偏移(d位)

由此得到三个最常用公式。

1. 最大页面数

页号有 (n-d) 位,所以最多有:

[
2^{n-d}\text{ 页}
]

例如,地址长度为3字节,即24位,页内偏移占10位:

[
页号位数=24-10=14
]

[
最大页面数=2^{14}=16384
]

2. 页面大小

若系统按字节编址,一个地址对应1字节,则:

[
页面大小=2^d\text{ 字节}
]

例如页内偏移为10位:

[
页面大小=2^{10}\text{B}=1\text{KB}
]

如果一个地址对应 (k) 字节,则必须乘上每个地址包含的字节数:

[
页面大小=2^d\times k\text{ 字节}
]

例如页内偏移为10位,每个地址访问4字节:

[
2{10}\times4=2\times22=2\text{B}
]

3. 进程最大容量

若按字节编址,(n) 位逻辑地址能够表示 (2^n) 个字节地址,所以:

[
进程最大容量=2^n\text{ 字节}
]

也可以通过“页数乘页面大小”计算:

[
2{n-d}\times2d=2^n
]

以24位地址、10位页内偏移为例:

问法 结果
最多有多少页 (2^{14}) 页
每页多大 (2^{10}) B
进程最大多少字节 (2^{24}) B

这三种问题使用的是同一组数据,但答案并不相同。


三、逻辑地址到物理地址:操作系统管理,MMU执行

页式系统中,逻辑地址由页号和页内偏移组成。页表负责把逻辑页号映射成物理页框号:

逻辑地址:页号 p | 页内偏移 d
                 ↓ 查页表
物理地址:页框号 f | 页内偏移 d

物理地址公式为:

[
物理地址=页框号\times页面大小+页内偏移
]

页内偏移在转换前后保持不变,改变的只是页号到页框号的映射。

谁负责地址转换?

  • 操作系统负责创建、维护页表,分配页框,并处理缺页中断。
  • MMU(内存管理单元)负责程序运行期间的实际地址转换。

因此,“地址转换完全由操作系统逐次完成”是错误的。更准确的说法是:操作系统管理转换所需的数据结构,硬件 MMU 执行高频转换。

页表基址寄存器在进程运行时指向当前页表;进程切换时,它的值作为进程现场的一部分被保存和恢复,相关信息通常保存在 PCB 中。

静态重定位与动态重定位

方式 转换时机 特点
静态重定位 程序装入内存时 一次性修改地址,装入后通常不能随意移动
动态重定位 程序运行时 每次访问时由硬件转换,可使用基址寄存器
基址寄存器 + 转换线路 运行时 动态重定位的一种硬件实现

“动态分区”和“静态分区”属于内存分配方式,不属于地址转换方式。


四、多级页表:页内偏移永远取地址最低位

假设一个32位逻辑地址被划分为:

页目录位移10位 | 页表位移10位 | 页内位移12位

那么页内地址就是逻辑地址最右边的12位。无论一级页表还是多级页表,页内偏移都位于低位,因为它表示页面内部的位置。

例如:

1101000110 | 1101101010 | 110001010011
                            ^ 最右12位

将最后12位按每4位一组转换成十六进制:

1100 0101 0011 = C53H

所以该地址的页内地址为 C53H


五、页表项中到底保存什么

简单页式管理假设页面都在内存中,页表最核心的信息是页框号。发展到虚拟页式后,页面可能不在内存,还可能被访问、修改和淘汰,因此典型页表项通常包含:

字段 含义 作用
页框号 页面所在的物理页框 形成物理地址
有效位/存在位 页面是否在内存中 判断是否发生缺页
修改位/脏位 页面调入后是否被修改 决定淘汰时是否写回磁盘
访问位/引用位 页面近期是否被访问 供 NRU、Clock 等算法使用
保护位 是否允许读、写、执行 内存保护

从简单页式发展到虚拟页式时,考试通常认为新增的是:

  • 有效位(存在位);
  • 修改位;
  • 访问位(引用位)。

磁盘始址不一定直接保存在每一个页表项中,也可以由页号推导或由其他外存管理结构记录,所以不能一概认为它是每个页表项的必备字段。

“停止位”属于串行通信概念,“校验位”用于错误检测,都不是虚拟页式管理为了页面置换而新增的典型字段。


六、快表 TLB:减少查页表的内存访问

普通一级页表存放在内存时,一次数据访问通常需要:

  1. 访问内存中的页表;
  2. 根据页框号再次访问真正的数据。

若内存访问时间为 (m),不用快表的时间为:

[
2m
]

设快表查询时间为 (t),命中率为 (h)。采用完整计时模型:

  • 快表命中:(t+m);
  • 快表未命中:(t+2m)。

平均访问时间为:

[
EAT=h(t+m)+(1-h)(t+2m)
]

例如 (m=40ns)、(t=8ns)、(h=90%):

[
EAT=0.9\times48+0.1\times88=52ns
]

相对于不用快表的80ns,严格计算下降:

[
\frac{80-52}{80}=35%
]

部分题库采用简化口径:未命中时仍按原来的80ns计算,不额外加入8ns快表查询时间。此时:

[
EAT=0.9\times48+0.1\times80=51.2ns
]

[
下降比例=\frac{80-51.2}{80}=36%
]

因此遇到选项只有36%而没有35%时,题库采用的是后一种简化模型。快表有多少个单元,在已经直接给出命中率且不问覆盖范围时,通常是干扰信息。


七、页面置换算法:先认英文缩写,再看对应字段

页面置换算法最容易被中文名称误导。正确的判断依据如下:

算法 英文含义 真正比较的内容
OPT Optimal 将来最晚使用或不再使用
FIFO First In First Out 最早调入内存
LRU Least Recently Used 最近一次使用距现在最久
LFU Least Frequently Used 统计周期内访问次数最少
NRU Not Recently Used 访问位和修改位分类
Clock 时钟算法 循环扫描访问位

1. LRU:看“多久没用”,不是“用了几次”

LRU 的准确含义是“最近性最低的页面”,即最近一次被访问的时间距离当前最远。

中文“最近最少使用”容易被错误断句。这里的 Least 修饰的是 Recently,不是访问次数:

Least Recently Used
= 最不近期被使用
= 最近最长时间没有被使用

严格的 LRU 需要最近访问时间、时间戳、栈等历史信息。访问位只有0和1,只能说明某段时间内是否访问过,不能精确给出访问先后;调入内存时间则是 FIFO 的依据,不是严格 LRU 的依据。

有些考试题没有给最近访问时间,只给访问位和调入时间,并约定“先在访问位为0的页面中选择,再挑调入最早的页面”。这只能视为题库自定义的近似规则,不能反过来当作 LRU 的标准定义。

2. LFU:看“用了多少次”

LFU 中的 FFrequently,表示频率。题目通常直接给出“T时间内访问次数”,选择次数最小的页面。

例如四个页面的访问次数分别是50、86、22、78,则应选择访问22次的页面。即使该页面访问位为1,也不矛盾:

  • 访问位为1:最近某段时间至少访问过一次;
  • 访问次数为22:整个统计周期内总共访问22次。

“最近访问过”和“总体访问次数最少”可以同时成立。

3. NRU:看访问位 R 和修改位 M

NRU 按照 ((R,M)) 将页面分为四类,淘汰优先级通常为:

  1. ((0,0)):未访问、未修改;
  2. ((0,1)):未访问、已修改;
  3. ((1,0)):已访问、未修改;
  4. ((1,1)):已访问、已修改。

优先淘汰 ((0,0)),因为它近期没有被使用,而且淘汰时不需要写回磁盘。

4. OPT:看未来

OPT 在发生缺页且页框已满时,淘汰“未来最晚才会再次访问”或“以后不再访问”的页面。它通常用于理论比较,因为真实系统无法预知完整未来。

例如3个空页框,页面序列为:

0, 6, 0, 1, 5, 1, 5, 4, 1, 2, 5, 2, 4, 5, 2, 3, 5, 3

发生缺页的位置为第1、2、4、5、8、10、16次访问,共7次。开始时页框为空,首次装入页面也要计算缺页。

一句话记忆

FIFO 看谁先进来
LRU  看谁最久没用
LFU  看谁使用次数最少
NRU  看访问位和修改位
OPT  看谁未来最晚再用

八、CPU 利用率、磁盘繁忙率与进程数量

虚拟存储系统中,可以通过 CPU 利用率和磁盘繁忙率判断多道程序度是否合适。

CPU利用率 磁盘繁忙率 可能情况 调整方向
可运行进程太少,资源都在空闲 适当增加进程
很高 频繁换页,可能发生抖动 减少进程
资源利用较充分 通常不调整

例如 CPU 利用率50%、磁盘繁忙率3%,两者都不高,说明系统不是被磁盘拖慢,也不像发生了抖动,更可能是可运行进程太少。适当增加进程,可以在一个进程等待 I/O 时让另一个进程使用 CPU。

更换更快的 CPU 不能解决“CPU 本身有一半时间空闲”的问题;磁盘繁忙率只有3%时,更换更快的磁盘同样没有明显意义。


九、数组访问与缺页:关键是存储顺序和访问顺序是否一致

数组缺页题必须先确定:

  1. 数组按行还是按列连续存放;
  2. 一行有多少元素;
  3. 一页能装多少元素;
  4. 循环中哪个下标变化最快;
  5. 数据实际可用多少个页框。

对于按行存放的二维数组 A[300][100],一行有100个整数。若一页能放300个整数,则一页正好容纳3行:

第0页:第1、2、3行
第1页:第4、5、6行
……
第99页:第298、299、300行

若程序外层循环是列 j=1..100,内层循环是行 i=1..300,则固定一列时的访问页面序列为:

第0页、第0页、第0页、
第1页、第1页、第1页、
……、
第99页、第99页、第99页

因此每一列缺页100次,共100列:

[
100\times100=10000\text{次}
]

如果题库给出的答案是 (300\times100=30000),它等价于假设每一次数组访问都进入不同页面。这只有在“一页仅容纳一行,即一页存100个整数”等条件下才成立,与“一页存300个整数”矛盾。遇到这种情况应判定为题目数值修改后答案未同步,而不是强行套参考答案。

这类题体现的是局部性原理:程序访问顺序与数据连续存放顺序一致时,缺页少;跨行、跨页跳跃访问时,缺页多。


十、分段与段页式管理

1. 分段

分段按照程序的逻辑结构划分,例如代码段、数据段、栈段。逻辑地址通常表示为:

段号 | 段内偏移

段表项包含段基址和段长。地址转换与保护过程为:

  1. 用段号查段表;
  2. 检查段内偏移是否小于段长;
  3. 物理地址 = 段基址 + 段内偏移。

如果程序从60K开始,到124K结束,则:

[
基址=60K
]

[
限长=124K-60K=64K
]

基址寄存器保存起始位置,限长寄存器保存允许访问的范围,不应把结束地址124K直接当作限长。

2. 段页式

段页式先按照逻辑关系分段,再将每一段划分成固定大小的页:

逻辑地址:段号 | 段内页号 | 页内偏移
查找过程:段表 → 该段的页表 → 物理页框

其关键特点是:

  • 逻辑上分段,便于保护和共享;
  • 物理上分页,内存以固定大小页框管理;
  • 每个进程有一张段表,每个段对应一张页表;
  • 克服了分段方式的外部碎片,但最后一页仍可能产生内部碎片。

所以“段页式的物理内存按段管理,与可变分区相同”是错误的。


十一、连续分区分配算法

连续分区题要区分“选择哪个空闲分区”,而不是地址转换。

算法 选择规则
首次适应 First Fit 从头查找第一个足够大的空闲分区
下次适应 Next Fit 从上次查找结束位置继续寻找
最佳适应 Best Fit 选择能满足要求的最小空闲分区
最坏适应 Worst Fit 选择当前最大的空闲分区

例如初始空闲区大小为:

10KB、100KB、70KB、130KB、22KB

进程 P7 请求40KB,若系统选择130KB空闲区,留下90KB;随后 P8 请求10KB,又选择当时最大的100KB空闲区,留下90KB。这说明系统每次都选择最大的空闲区,使用的是最坏适应算法。

最佳适应在 P7 请求40KB时会选择70KB空闲区,而不会选择130KB。


十二、高频名词对照表

名词 对应信息 不要混淆成
页号 逻辑页面编号 页框号
页框号 物理内存块编号 页号
页内偏移 页面内部位置 页面数量
调入时间 页面进入内存的时间 最近访问时间
最近访问时间 上一次使用页面的时间 访问次数
访问位 某周期是否访问过,0或1 精确访问时间
修改位 页面是否被写过 页面是否被访问
T时间内访问次数 统计周期内访问频率 页面的驻留时间
有效位/存在位 页面是否在内存 地址是否合法的所有含义
基址 段或分区的起始地址 段长
限长 可访问范围的长度 结束地址

十三、统一做题流程

地址位数题

  1. 把字节数换成位数,例如3字节等于24位;
  2. 总位数减去页内偏移位数,得到页号位数;
  3. 看清题目问页数、页大小还是总容量;
  4. 检查每个地址对应1字节还是多个字节。

页面置换题

  1. 先认英文缩写;
  2. 确认页框初始是否为空;
  3. 命中不算缺页;
  4. 缺页且页框未满时直接装入;
  5. 页框已满时,严格按照该算法选择淘汰页;
  6. 不要拿访问次数回答 LRU,也不要拿访问位回答 LFU。

数组缺页题

  1. 写出数组在内存中的连续顺序;
  2. 算出一页容纳几行或几个完整数据块;
  3. 写出前几次访问对应的页号;
  4. 再按页框数和置换算法统计;
  5. 如果参考答案与页号序列直接矛盾,应检查题库条件是否修改错误。

分区分配题

  1. 列出所有空闲分区及大小;
  2. 按进程请求顺序逐个分配;
  3. 观察每次选择的是第一个、最小、最大,还是从上次位置继续;
  4. 每次分配后立即更新剩余空闲区。

十四、最后的核心口诀

地址总位数 = 页号位数 + 页内偏移位数
页面大小 = 页内地址数 × 每个地址的字节数
进程容量 = 页面数 × 页面大小

操作系统管理页表,MMU执行地址转换
页内偏移取逻辑地址最低位

FIFO 看进入时间
LRU  看最近一次使用时间
LFU  看统计周期内访问次数
NRU  看访问位和修改位
OPT  看未来最晚使用时间

逻辑上分段,物理上分页
最佳适应选最小,最坏适应选最大

只要先判断题目正在比较“时间、次数、状态位、地址位数还是空闲分区大小”,大多数存储管理题都可以落入上面的固定框架中。

posted @ 2026-07-28 01:12  ziziranran  阅读(6)  评论(0)    收藏  举报
下面这份是完整代码,已经把《失语者 - 蔡健雅》放在第一首,并把 `loop` 改成 `none`,这样播完第一首会继续切到后面的歌。 ```html
```