学习日期:2024.6.20
内容摘要:基本分页存储管理的概念
在上一章中我们学习了内存的连续分配管理方式,下面我们将学习非连续的内存分配管理方式。非连续分配管理方式主要有基本分页存储管理、基本分段存储管理、段页式存储管理
本章我们学习基本分页存储管理
什么是分页存储?
将内存空间分为一个个大小相等的分区,每个分区就是一个“页框”(页框=页帧=内存块=物理块),每个页框有一个编号,从0开始。
将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个“页”或者“页面”,每个页面也有一个编号,从0开始。
注意!页框和页不一样,单字“页”是指页面,是进程的逻辑地址空间的区块,而页框即“内存块”,是内存空间的分区。
页框就好比分好了格子的货架,而页就是大小正好能放进格子里的货物。
操作系统以页框为单位,将进程的每个页面都分别放入一个页框中一一对应,进程的各个页面不必连续存放,可以放到不相邻的页框中,这样就实现了非连续的内存管理。
页表——对应关系的记录者
为了能知道进程的每个页面在内存块中存放的位置,操作系统要为每个进程建立一张页表,通常保存在PCB(进程控制块)中。
一个进程对应一张页表,进程的每个页面对应一个页表项,每个页表项由页号和块号组成,记录进程页面与实际存放的内存块(页框)之间的映射关系。
1.每个页表项多大?占几个字节?
eg.设某系统物理内存大小为4GB,页面大小为4KB,则每个页表项至少应该为多少字节?
内存块大小=页面大小=4KB=2^12B
2^32/2^12=2^20 故内存块号的范围应该是0~2^20-1
内存块号至少要用20bit表示,故至少要用3B来表示块号。
因为页表项连续存放,因此页号可以是隐含的,不占存储空间。(类比数组,知道首地址)
i号页表项存放地址=页表起始地址+i*页表项大小
因此,每个页表项占3B,存储整个页表要3*(n+1)B
2.如何实现逻辑地址到物理地址的转换?
虽然进程的各个页面是离散存放的,但是页面内部是连续存放的,如图
要访问逻辑地址A,则先确定其对应的页号P,再查页表找到P号页面在内存中的起始地址,确定逻辑地址A的页内偏移量W。
逻辑地址A对应的物理地址=P号页面在内存中的起始地址+页内偏移量W
如何确定页号P和业内偏移量W?
俄罗斯套娃——两级页表
单级页表存在的问题
某32位计算机系统按字节寻址,采用分页式存储管理,页面大小4KB,页表项长度为4B
4KB=2^12B,因此页内地址要用12位表示,剩余20位表示页号
因此,该系统中用户进程最多有2^20页,由因为表项长度位4B,所以一个页表最大需要2^20*4B=2^22B,共需要2^22/2^12=2^10个页框存储该页表
根据页号查询页表的方法必须要页表项连续存放,所以要准备2^10即1024个连续的页框来存放页表
省流:页表占的地方太大了,还必须要连续空间来存放,违背了非连续内存管理的初心
根据局部性原理(详见【内存的扩充技术】),进程在一段时间内只需要访问某几个界面就可以正常运行了,没有必要让整个页表都常驻内存。
回顾:我们是如何解决进程在内存中必须连续存储的问题的?——将进程地址空间分页,并且为其建立一张页表,记录各页面的存放位置。
所以......我们可以套娃!
可以将长长的页表分组,使得每个内存块恰好可以放入一个分组,再为这个分好组的页表,再建立一个“页表的页表”,称为“页目录表”或是“外层页表”
例:
页号 | 块号 |
---|---|
0 | 2 |
1 | 4 |
... | ... |
1024 | 762 |
... | ... |
2^20-1 | ... |
再把这个足足有2^20行的大页表拆成2^10个2^10行的小页表
0 | 2 |
1 | 4 |
... | ... |
1023 | ... |
0 | 762 |
1 | ... |
1023 | ... |
拆出来2^10个这样类似的小页表
再建立一个页目录表,把页表所存储到的内存块号和页表号一一对应
页表号 | 内存块号 |
0 | 3 |
1 | ... |
... | ... |
1023 | ... |
两级页表如何实现地址变换?
①按照地址结构将逻辑地址拆分成三部分
②从PCB中读出页目录地址,根据一级页号查页目录表,找到下一级页表在内存中的位置
③根据二级页号查表,找到最终想访问的内存块号
④结合页内偏移量得到物理地址
为什么多出来一个二级页表,反而占的内存少了?
有人可能会疑惑,分了二级表,映射 4GB 地址空间就需要 4KB(一级页表)+ 4MB(二级页表)的内存,这样占用空间不是更大了吗?
还记得局部性原理吗?我们不需要把整个页表都装入内存,只需要把一级页表常驻,如果使用了二级分页,一级页表就可以覆盖整个 4GB 虚拟地址空间,但如果某个一级页表的页表项没有被用到,也就不需要创建这个页表项对应的二级页表了,即可以在需要时才创建二级页表。
假设只有 20% 的一级页表项被用到了,那么页表占用的内存空间就只有 4KB(一级页表) + 20% * 4MB(二级页表)= 0.804MB
,这对比单级页表的 4MB
是不是一个巨大的节约?
为什么单级页表不能用局部性原理,部分装入内存来节省空间?
从页表的性质来看,保存在内存中的页表承担的职责是将虚拟地址翻译成物理地址。假如虚拟地址在页表中找不到对应的页表项,计算机系统就不能工作了。所以页表一定要覆盖全部虚拟地址空间,不分级的页表就需要有 100 多万个页表项来映射,而二级分页则只需要 1024 个页表项(此时一级页表覆盖到了全部虚拟地址空间,二级页表在需要时创建)。
我们甚至还可以把二级分页再推广到多级页表(更多的套娃!),这样页表占用的内存空间就更少了,但是也不能无限套下去,因为更多的套娃意味着更长的查询时间。
这一切都要归功于对局部性原理的充分应用。
内容总结自王道计算机考研《操作系统》 和 人民邮电出版社《操作系统导论》