背景
连续分配的缺点:
物理内存必须连续
存在外碎片和内碎片
内存分配的动态修改困难
内存利用率较低
非连续分配的设计目标
目标:提高内存利用效率和管理灵活性
允许一个程序使用非连续的物理地址空间
允许共享代码与数据
支持动态加载和动态链接
非连续分配需要解决的问题
何实现虚拟地址和物理地址的转换(不同的逻辑地址可能位于不连续的物理区域中)
软件实现(灵活,开销大)
硬件实现(够用,开销小)
如何选择非连续分配中的内存分块大小
- 段式存储管理(segmentation):块大
- 页式存储管理(paging):块小
段式存储
进程有哪些段
代码段(公用库代码段、子模块代码段、主代码段)
堆栈段(stack)
堆数据(heap)
初始化数据段
BSS段(存放未初始化的全局变量)
段的概念
段表示访问方式和存储数据等属性相同的一段地址空间
对应一个连续的内存“块”
若干个段组成进程逻辑地址空间
段访问:逻辑地址由二元组(s,addr)表示;“段基址+段内偏移”
段访问的硬件实现
首先从逻辑地址中得到段号和偏移量
在段表中查找段号,得到段基址和段长度
由MMU来判断偏移量是否合法(偏移量是否大于段长度)
得到物理地址,在物理内存中查找相应内容
页式存储
页式存储概念
页帧(帧是物理的)
把物理地址空间划分为大小相同的基本分配单位
2的n次方,如512,4096,8192,4k是常用大小
地址可以表示成二元组(f,o);“帧基址(帧号*帧大小)+帧内偏移”
页面(页是逻辑的)
把逻辑地址空间也划分为相同大小的基本分配单位
帧和页的大小必须是相同的
页表
保存页号与帧号之间的映射关系
页表结构
每个进程都有一个页表
随进程运行状态而动态变化(可以动态调整内存空间大小)
页表基址寄存器:PTBR(存放页表起始位置)
页表项的组成
每个页面对应一个页表项
帧 号:f
存在位:逻辑页面是否存在与之对应的物理帧(有些逻辑页没有对应的物理帧)
修改位:对应的页面中的内容是否被修改了
引用位:在过去一段时间内是否访问过页中的某一个存储单元
页式存储的性能问题
访问一个内存单元需要2次内存访问:第一次访问:获取页表项,第二次访问:获取数据
页表可能非常大:64位机器如果每页1024字节,则页表的大小为2^54*8
页式存储的性能优化
快表(TLB):缓存
缓存近期访问的页表项
关联存储器:有一组key,可以并行地查找所有表项,得到匹配项
快表位于CPU中,所以它的速度快、成本高、功耗大
如果TLB未命中,再访问页表,对应的表项被更新到TLB中
多级页表:
通过间接引用将页号分成k级,建立页表“树”。
减少了空页表项,节约空间。但大地址空间(64-bits)系统,多级页表变得 繁琐。
反置页表:hash
页表项与帧做对应
页寄存器(一个帧对应一个页寄存器)的内容包括
使用位(Residence bit):此帧是否被进程占用
占用页号(Occupier):对应的页号p
保护位(Protection bits):约定这一页的访问方式,可读,可写……
页寄存器中的地址转换:对逻辑地址进行*Hash映射,以减少搜索范围
页寄存器搜索步骤
对逻辑地址进行Hash变换
在快表中查找对应页表项
有冲突时遍历冲突项列表
查找失败时,产生异常
反置页表的优缺点
优点:页表小
缺点:需要搜索页寄存器
段页式存储
什么是段页式存储管理
在段式存储管理基础上,给每个段加一级页表
逻辑地址:段号+若干个页号+页内偏移
物理地址:帧号+页内偏移
段页式存储管理中的内存共享(同表):通过指向相同的页表基址,实现进程间的段共享,共享段指向同一个页表