分页存储管理¶
约 1253 个字 5 行代码 6 张图片 预计阅读时间 4 分钟
逻辑地址与物理地址¶
- 逻辑地址(Logical Address),也称虚拟地址,是程序在编译后生成的地址,它是相对于程序开始位置的偏移地址。
- 每个编译生成的目标模块中的指令和数据,都是从 0 单元开始编号,这就形成了所谓的逻辑地址空间。
- 物理地址(Physical Address)是程序最终被加载到内存后,在真实内存空间中的地址位置。
- 操作系统会决定程序被装入内存的实际起始位置,因此物理地址并不总是从 0 开始。
逻辑地址 → 通过装入时的基址 → 转换为物理地址。
Text Only | |
---|---|
一个例子
-
一个程序被编译成目标模块后,其中某条指令的逻辑地址是 95。
-
链接后形成完整的装入模块,被操作系统加载到内存地址 100。
-
则该指令的物理地址为:
Text Only | |
---|---|
基本分页存储原理¶
连续分配的局限性¶
- 单一连续分配
- 固定分区分配
- 动态分区分配
存在的问题:
- 外部碎片:内存中有足够的空闲空间,但因不连续而无法满足大块申请。
- 内部碎片:为进程分配的内存比其实际需求多,造成浪费。
分页存储管理¶
核心思想:
将内存和进程都划分为固定大小的块,使二者可以一一对应,实现非连续分配,消除外部碎片。
分块方式:
对象 | 块名 | 英文术语 | 特点 |
---|---|---|---|
进程 | 页(Page) | Page | 大小固定,通常为 2 的整数次幂 |
内存 | 页框 | Page Frame | 又称页帧 / 物理块,大小等于页大小 |
外存 | 盘块 | Block | 在分页管理中通常不涉及直接映射 |
分页管理的优点
- 避免外部碎片
- 各页可以分散在不同内存块中,不要求连续,天然解决外部碎片问题。
- 内部碎片极小
- 最多只有最后一页未满,可能会浪费一点空间,称为页内碎片(业内碎片)。
- 支持动态内存分配
- 页与页框一一映射,进程调入时无需全部就绪(支持请求分页)。
逻辑地址结构¶
如果希望访问逻辑地址 x = 58
- 确定它来自哪个页面 (页号)
- 确定它在该页面中的地址 (页内偏移量)
- 确定所在页面在内存中的起始地址
x 对应的物理地址 = 所在页面在内存中的起始地址 + 页内偏移量
假设在 32 位环境下,虚拟地址空间共有 4GB(2^32),假设一个页的大小是 4KB (2^12),那么就需要大约 100 万 (2^20) 个页,每个「页表项」需要 4 个字节大小来存储,那么整个 4GB 空间的映射就需要 4MB 的内存来存储页表。
页表¶
为了方便在内存中找到进程的每个页面对应的页框,OS 为每个进程建立一张页表,放在内存中。
页号 <=> 页框号
- 页表:系统为每个进程建立的页面映像表,即上图中一整块部分。
- 页表项:页表的其中一项,即上图中一整块部分的其中一行(如:页号为 0且物理块号为 2的整体为一个页表项)。
- 页表项大小:上图中一整块部分的其中一行所占大小。
- 页表长度:指页表项的个数,即上图中一共有几行,有几行页表长度就为多少。
基本地址变换机构¶
在系统中通常设置一个页表寄存器 (PTR),存放页表在内存的起始地址 F 和页表长度 M。进程未执行时,页表的始址和页表长度存放在本进程的 PCB 中,当进程被调度执行时,才将页表始址和页表长度装入页表寄存器中。
设页面大小为 L,逻辑地址 A 到物理地址 E 的变换过程如下:
- 计算页号 P (P = A / L) 和页内偏移量 W (W = A % L)
- 比较页号 P 和页表长度 M,若 P >= M (页号从 0 开始),则产生越界中断,否则继续执行
- 页表中页号 P 对应的页表地址 = 页表始址 F + 页号 P * 页表项长度,取出该页表项内容 b,即为物理块号。注意区分页表长度和页表项长度。页表长度是指一共有多少页,页表项长度是指页地址占多大的存储空间。
- 计算 E = b * L + W,用得到的物理地址 E 去访问内存。
如果内存块号,页面偏移量是二进制表示的,那么将它们拼接起来就可以得到物理地址。
例题:若页面大小 L 为 1k 字节,页号 2 对应的内存块号 b=8,将逻辑地址 A=2500 转换为物理地址 E
答: