之前的技术
覆盖:模块粒度,需要确定各个模块的关系,增加了程序员的负担
交换:进程粒度,需要把整个进程的地址空间换进换出,增加了处理器的开销
页式虚拟存储器
一丶工作流程
起始:用户进程需要调入内存运行时,装入一部分程序放入个别的页,有一部分不在了内存
后续:当CPU需要访问的内容不在内存中时候,会给操作系统发送一个缺页异常,OS就会根据产生异常的地址,找到对应硬盘的数据调入内存中,如果这时候可以使用的内存满了,就需要页面置换换出内存中的一些位
具体:
- CPU装载某个内存地址的内容,会去查看页表
- 如果地址中页表的存在位为0,发生缺页异常,然后交给OS工作,
- 首先看内存中是否有空闲的物理页,就会分配一个空闲的物理页帧,然后把访问的地址对应硬盘中的数据以页的单位读到刚刚你分配的地方,修改页表项,把存在位设置为1,之后跳回刚刚产生异常的指令,重新执行,这次CPU就可以正常访问
- 如果没有空闲的,就是用页面置换算法把某个物理页的数据清空,注意如果修改过,就需要写回到硬盘再清空,如果没有被修改,就直接释放掉,然后把使用的页变成空闲状态,,然后把访问的地址对应硬盘中的数据以页的单位读到刚刚你分配的地方,修改页表项,把存在位设置为1,之后跳回刚刚产生异常的指令,重新执行,这次CPU就可以正常访问
二丶地址转换
页表的索引对应页号,看存在位是否存在,不存在就会异常,存在就就能找到帧号,完成映射,页表是OS在初始化的时候就建立好的
三丶页表项
虚拟页式内存管理,页表项增加了几个位,更方便虚拟内存管理
页的大小固定的
页帧:物理地址空间划分为大小相同的基本分配单位
页面:逻辑地址空间划分为大小相同的基本分配单位
四丶页表用来映射但是存在一些问题:
- 空间问题:64位寻址如果每页1024字节,那么页表项254项为会非常大,每个程序都有一个页表
- 时间开销问题:页表太大CPU内放不下的话,所以放在内存中,这样一次访存会变成两次访问,
1. 时间解决:Cache或者间接访问(多级页表)
间接访问
CPU的MMU有TLB(Translation Look-aside Buffer)
TLB将经常使用的页表项存储进来,所以CPU可以直接在TLB查,假如查不到就再去内存中的页表,然后需要将页表中的项还需要存储到TLB中
2. 空间问题解决:
建立多级页表
地址分块,查找一级页表的p1对应的页表项,存储的是二级页表的起始地址再加p2,得到第三级页表的起始地址,如果p1中某个页表项的驻留位为0,那么整个二级页表的就不需要了,节省了空间
一级页表中不存在的对应的第二级页表可以删去