操作系统 6 物理内存管理:非连续内存分配
6 物理内存管理:非连续内存分配
6.1 非连续内存分配的需求背景
6.1.1 非连续分配的设计目标
连续分配的缺点
- 分配给程序的物理内存必须连续
- 存在外碎片和内碎片
- 内存分配的动态修改困难
- 内存利用率较低
非连续分配的设计目标
提高内存利用效率和管理灵活性
- 允许一个程序使用非连续的物理地址空间
- 允许共享代码和数据
- 支持动态加载和动态链接
6.1.2 非连续内存分配的实现
非连续分配需要解决的问题:如何实现虚拟地址和物理地址的转换
- 软件实现:灵活,但开销大
- 硬件实现:够用,开销小
非连续分配的硬件辅助机制:如何选择非连续分配中的内存分块大小
- 段式存储管理
- 页式存储管理
6.2 段式存储管理
6.2.1 段地址空间
进程的段地址空间由多个段组成
- 主代码段
- 子模块代码段
- 公用库代码段
- 堆栈段
- 堆数据
- 初始化数据段
- 符号表等
段式存储管理的目的:更细粒度和灵活的分离与共享
段地址空间是不连续的二维结构
6.2.2 段访问机制
段的概念
- 段表示访问方式和存储数据等属性相同的一段地址空间
- 对应一个连续的内存块
- 若干个段组成进程逻辑地址空间
段访问:逻辑地址由二元组(s, addr)表示
- s : 段号
- addr : 段内偏移
段访问的硬件实现
段表的每个条目都有段基地址(该段在内存中开始的内存地址)和段界限(长度)
6.3 页式存储管理
6.3.1 页式存储管理
页帧
- 把物理地址空间划分为大小相同的基本分配单位
- 2的n次方,如512,4096,8192
页面
- 把逻辑地址空间也划分为相同大小的基本分配单位
- 帧和页的大小必须是相同的
页面到页帧
- 逻辑地址到物理地址的转换
- 页表
- MMU/TLB
6.3.2 帧 Frame
物理内存被划分成大小相等的帧
内存物理地址的表示:二元组 (f, o)
f: 帧号 (F位, 共有 \(2^F\) 个帧)
o:帧内偏移(S位,每帧有 \(2^S\)字节)
物理地址 = f * \(2^S\) + o
基于页帧的物理地址计算实例
在16-bit的地址空间,9-bit大小的页帧下
物理地址表示 = (3,6)
物理地址 = f * \(2^S\) + o
实际物理地址 = 512 * 3 + 6 = 1542
6.3.3 页 Page
进程的逻辑地址空间被划分为大小相当的页
页内偏移 = 帧内偏移
通常 页号大小 \(\neq\) 帧号大小
进程逻辑地址的表示:二元组 (p, o)
p: 页号 (P位,代表共有 \(2^P\)个页)
o: 页内偏移 (S位,每页有 \(2^S\)字节)
虚拟地址 = p * \(2^S\) + o
页式存储中的地址映射
- 页到帧的映射
- 逻辑地址中的页号是连续的
- 物理地址中的帧号是不连续的
- 不是所有的页都有对应的帧
6.3.4 页表
页表保存了逻辑地址——物理地址之间的映射关系
6.4 页表概述
6.4.1 页表结构
每个进程都有一个页表
- 每个页面对应一个页表项
- 随进程运行状态而动态变化
- 页表基址寄存器(PTBR:Page Table Base Register)
- 当页表非常大时,需要将页表放入内存中,并用PTBR指向页表。改变页表只需要改变这一寄存器即可,大大降低了切换时间
页表项组成:
- 帧号:f
- 页表项标志
- 存在位:用于指示该页是否已调入内存
- 修改位:表示该页在调入内存后是否被修改过
- 引用位:用于记录本页在一段时间内被访问次数
页表地址转换示例
可见,4是没有放入内存中,3已放入内存了。
6.4.2 页式存储管理机制的性能问题
内存访问性能问题
- 访问一个内存单元需要2次内存访问
- 第一次:获取页表项
- 第二次:访问数据
页表大小问题:
- 页表可能非常大
- 64位机器每页1024个字节,一个页表大小为:3+54=57位。 2的57次幂!
如何处理?
- 缓存
- 间接访问
6.5 快表和多级页表
6.5.1 快表(TLB)
缓存近期访问的页表项。
如果TLB命中,物理页号可以很快被获取
如果TLB未命中,对应的表项被更新到TLB中。
- TLB:转换表缓冲区。TLB条目有键、值组成,可以快速查找页表,但条目数不多,为64~1024之间。
- TLB只包括页表中的一小部分条目,当CPU产生逻辑地址后,其页号提交给TLB。如果找到页号,那么也就得到了帧号。
- 如果页码不在TLB中(即TLB失效),那么就需要访问页表。当得到帧号后,可以访问内存。同时页号和帧号都会增加到TLB中,下次再用就可以快速查找到。如果TLB中的条目已满,那么操作系统就会选择一个来替换。
6.5.2 多级页表
通过间接引用将页号分成k级
- 建立页表树
- 减少每级页表长度
两级页表实例
6.6 反置页表
大地址空间问题
对于大地址空间系统,多级页表变得繁琐。
比如5级页表,逻辑(虚拟)地址空间的增长速度快于物理地址空间。
因此,有一种新的思路: 页寄存器和反置页表
- 不让页表与逻辑地址空间的大小相对应
- 让页表与物理地址空间的大小相对应
6.6.1 页寄存器
每一个帧与一个页寄存器关联,寄存器内容包括:
使用位:此帧是否被进程占用
占用页号:对应的页号p
保护位
页寄存器示例
物理内存大小:4096 * 4096 = 4K * 4KB = 16MB
页面大小:4096 bytes = 4KB
页帧数:4096 = 4K
页寄存器使用的空间(假设每个页寄存器占8字节):
8 * 4096 = 32KB
页寄存器带来的额外开销:
32K/16M = 0.2%
虚拟内存的大小:任意
页寄存器方案的特征
优点
- 页表大小相对于物理内存而言很小
- 页表大小与逻辑地址空间大小无关
缺点
- 页表信息对调后,需要根据帧号可找页号
- 在页寄存器中搜索逻辑地址中的页号
6.6.2 页寄存器中的地址转换
CPU生成的逻辑地址如何找对应的物理地址?
- 对逻辑地址进行Hash映射,以减少搜索范围
- 需要解决可能的冲突
用快表缓存页表项后的页寄存器搜索步骤
- 对逻辑地址进行Hash变换
- 在快表中查找对应页表项
- 有冲突时遍历冲突项页表
- 查找失败时,产生异常
快表的限制
- 快表的容量限制
- 快表的功耗限制
6.6.3 反置页表
基于Hash映射值查找对应页表项中的帧号
每个元素有三个域:pid、页号、指向下一项的指针
- 进程标识与页号的Hash值可能有冲突
- 页表项中包括保护位、修改位、访问位和存在位等标识
反置页表的Hash冲突
6.7 段页式存储管理
在段式存储管理的基础上,给每个段加一级页表。
段页式存储管理中的内存共享
通过指向相同的页表基址,实现进程间的段共享。