非连续存储分配
需求背景
连续分配内存的缺点
- 分配给程序的物理内存必须连续
- 存在外碎片和内碎片
- 内存分配的动态修改困难
- 内存利用效率低
非连续分配的设计目标
提高内存利用效率和管理灵活性
- 允许一个程序使用非连续的物理地址空间
- 允许共享代码于数据
- 支持加载和动态链接
实现虚拟地址和物理地址的转换
- 软件实现(灵活,开销大)
- 硬件实现(够用,开销小)
如何选择非连续分配中的内存分块大小
- 段式存储管理(分的块比较大)
- 页式存储管理(分成的块更小)
段式存储管理
进程的段地址空间由多个段组成
- 主代码段
- 子模块代码段
- 共用库代码段
- 堆栈段
- 堆数据段
- 初始化数据段
- 符号表等
目的:更细粒度和灵活的分离与共享
将上面的各个段分开,在内存中可以存储在不同的物理地址空间块
段
概念
- 段表示访问方式和存储数据等属性相同的一段地址空间
- 对应一个连续的内存“块”
- 若干个段组成进程逻辑地址空间
段访问
- s——段号
- addr——段内偏移
- 操作系统设置段表(其实地址,段的长度)
- 先在段表中取出段的长度,然后由mmu(存储管理单元)跟程序的虚拟内存中的偏移量作比较,如果合法,就在MMU中通过段基址加上偏移量就得出了物理地址,进行访问。
页式存储管理
页帧
帧、物理页面、frame、page frame
物理内存被划分为大小相等的帧,用一个二元组进行表示(f,o)
f —— 帧号(F位,共有2^F个帧)
o —— 是页帧内的偏移量(S位,每帧有2^S字节)
物理地址 = f*2^S + o
页面
页、逻辑页面、page
虚拟内存被划分为大小相等的帧,也用二元组表示(p,o)
p —— 页号(P位, 2^P个页)
o —— 业页内偏移(S位,每页有2^S字节)
页号不等于帧号,但是页内偏移等于帧内偏移
页面到页帧之间的转换
逻辑地址的页号是连续的
物理地址的帧号是不连续的
不是所有的页号都有对应帧
页表
页表基址(页号排序的开始的位置),页号,帧号
将页号对应成页帧,然后通过偏移量使用上面的物理地址公式计算出真正的物理地址每个进程都有一个页表
页表随进程运行状态而动态变化
页表基址寄存器(PTBR)(intel处理器上是CR3寄存器)
页表项组成
帧号:f
页表项标志
- 存在位(是否给虚拟内存分配过存储空间)
- 修改位
- 引用位
如果内存非常的大,那么页表就有可能很大,此时的处理办法有:
- 缓存(块表)
- 间接访问(多级页表)
快表(TLB)
存在于CPU中,使用关联存储实现,具备快速访问性能为了减少堆内存的访问
- 每次通过页表获取页帧号的时候,会将此页帧号关联的页号页帧号存入块表
- 下一次进行访问内存的时候,会先扫描快表(CPU中式特别快的),如果有命中,那么物理页帧号将会很快获取
- 如果没有命中,则继续通过页表查询,并且再次向快表中加载关联存储
多级页表
通过间接引用将页号分成K级,以减少页表的长度
- 建立页表”树”
- 减少每级页表的长度
- 第一级页表的起始位置有页表基址寄存器存储,由第一级的页号决定第二级页表中的起始位置,第三级页表的起始位置由第二级页表决定,最后加上偏移量。
段表和页表的结合
再段式的存储管理基础之上,给每个段加一级页表
- 首先找到段表里面相应的段表项
- 段表项中对应的式页表的基址,然后加上偏移量,就可以找到真正的物理地址了。
让两个进程中的某个段表项指向同一块页表就可以实现一个共享内存。
现在大多数计算机都是使用段表和页表相互结合来管理内存空间的。