【操作系统】详解 分页与分段系统存储管理
分页存储管理
分页基本概念
将内存空间分为一个个大小相等的分区(比如每个分区 4KB),每个分区就是一个物理层面的页面即页框。每个页框有一个编号,即 “页框号”,页框号从 0 开始。
将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个 “页” 或 “页面”。每个页面也有一个编号,即 “页号”,页号也是从 0 开始。
操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,可以放到不相邻的各个页框中。
页表
为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表。一个进程对应一个页表,页表记录进程页面和实际存放的内存块之间的映射关系。

如何实现地址转换
虽然进程的各个页面是离散存放的,但是页面内部是连续存放的
如果要访问逻辑地址 A,则:
- 确定逻辑地址 A 对应的 “页号”p
- 找到 p 号页面在内存中的起始地址(需要查页表)
- 确定逻辑地址 A 的 “页内偏移量”W
页号 = 逻辑地址 / 页面长度
页内偏移量= 逻辑地址 % 页面长度
快表
快表,又称联想寄存器(TLB,translation lookaside buffer),是一种访问速度比内存快很多的高速缓存,用来存放最近访问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表。
流程:
1. 逻辑地址拆分
进程的逻辑地址被拆分为页号和页内偏移量。例如图中逻辑地址(0, 8),页号为0,页内偏移量为8。
2. 快表(TLB)查询
首先查询快表(Translation Lookaside Buffer,即 TLB):
快表是高速缓存,存储最近使用的 “页号 - 内存块号” 映射。
若快表命中(找到目标页号对应的内存块号),则无需访问内存中的页表。
3. 内存页表(慢表)查询
若快表未命中,则需要访问内存中的页表(慢表):
通过 “页表始址 + 页号” 的计算,找到该页号对应的内存块号。
同时,会将该 “页号 - 内存块号” 映射存入快表(利用局部性原理,提高后续访问效率)。
4. 物理地址合成与内存访问
将内存块号与页内偏移量相加,合成物理地址,最终通过物理地址访问内存中的 “目标页面”。
5. 越界检查
在地址转换过程中,会检查页号是否超过页表长度,若超过则触发越界异常。
这种设计通过快表缓存热点页表项,大幅减少了内存页表的访问次数,从而提升地址转换和内存访问的效率。
局部性原理
- 时间局部性:若程序执行了某条指令或访问了某个数据,不久后该指令或数据很可能再次被执行 / 访问。这源于程序中大量的循环结构,例如循环语句会重复执行同一组指令。
- 空间局部性:若程序访问了某个存储单元,不久后其附近的存储单元很可能被访问。这是因为很多数据在内存中是连续存放的,比如数组元素的连续存储。
两级页表
与两级页表相比,单级页表主要存在以下问题:
1. 内存占用效率低
单级页表需为进程整个虚拟地址空间预先分配页表项,即使大部分地址空间未被使用,也需保留对应的表项。
2. 页表存储的连续性要求高
单级页表必须连续存放在物理内存中。当页表规模较大时(如上述 32 位系统需 4MB 连续空间),在内存碎片较多的情况下,分配连续的大块内存难度极大,甚至可能因无法满足连续空间需求而导致页表无法创建。
3. 对稀疏地址空间的适应性差
进程的虚拟地址空间往往是 “稀疏” 的(如代码段、堆、栈之间存在大量未使用的地址区域),单级页表仍需为这些 “地址空洞” 保留页表项,进一步加剧内存浪费。
4. TLB(快表)利用率低(间接影响)
单级页表项数量庞大(如 64 位系统单级页表需252项),而 TLB 容量有限(仅几十到几百项),导致 TLB 无法缓存大量页表项,频繁触发 TLB 未命中,进而增加内存访问开销。
因此两级页表就是解决方案。可以将长页表分组,使每个内存块可以刚好放入一个分组,并且这些分组离散地存储在内存块中。然后为离散分配的分组在建立一张页表,即顶层页表或者页目录表。
- 顶层页表(一级页表,如页目录表):存储在物理内存的一个连续页框中,用于管理二级页表的索引。
- 二级页表:可离散存储在物理内存的不同页框中,每个二级页表对应进程虚拟地址空间的一个子区域,仅在需要时才会被分配到物理内存(按需分配)。

分段存储管理
进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从 0 开始编址。
内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。

段表
段表将段的逻辑地址映射到物理内存中,实现段的地址转换。

分段分页对比
- 页是信息的物理单位。分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户是不可见的。
- 段是信息的逻辑单位。分段的主要目的是更好地满足用户需求。一个段通常包含着一组属于一个逻辑模块的信息。分段对用户是可见的,用户编程时需要显式地给出段名。
- 页的大小固定且由系统决定。段的长度却不固定,决定于用户编写的程序。
- 分页的用户进程地址空间是一维的,程序员只需给出一个记忆符即可表示一个地址。
- 分段的用户进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,也要给出段内地址。
- 分段比分页更容易实现信息的共享和保护。不能被修改的代码称为纯代码或可重入代码(不属于临界资源),这样的代码是可以共享的。可修改的代码是不能共享的。
