内容系听课复习所做笔记,图例多来自课程截图
基本分页存储管理
两次访存,第一次查页表,第二次访问目标内存单元
将内存空间分为一个个大小相等的分区(比如每个分区4KB),每个分区就是一个“页框”(页框=页帧=内存块=物理块=物理页面)。每个页框有一个编号,即“页框号”(页框号=页帧号=内存块号=物理块号=物理页号),页框号从0开始。
将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个“页”或“页面”。每个页面也有一个编号,即“页号”,页号也是从0开始。
划重点,页面(是进程的概念,存在于逻辑地址空间)和页框(是物理空间)大小相等
因为大小相等才能一一对应过去。另一方面还要使用页表来记述进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表,页表通常在PCB中
- 一个进程对应一张页表
- 进程的每个页面对应一个页表项
- 每个页表项由“页号”和“块号”组成
- 页表记录进程页面和实际存放的内存块之间的映射关系
页表项所占字节数
页表举例:
页表 | 块号 |
---|---|
0 | 3 |
1 | 6 |
2 | 4 |
… | … |
n | 8 |
假设某系统物理内存大小为4GB,页面大小为4KB,则每个页表项至少应该为多少字节?
- 内存块大小=页面大小=4KB= 2 12 2^{12} 212 B
- 4GB的内存总共会被分为 2 32 / 2 12 = 2 20 2^{32} /2^{12}=2^{20} 232/212=220个内存块
- 内存块号的范围应该是 0 ∼ 2 20 − 1 0 \sim 2^{20}-1 0∼220−1
- 内存块号至少要用 20 bit来表示,但是计算机分配储存空间是按字节而非比特
- 至少要用3B来表示块号(3*8=24bit)
但是在存储时,由于连续存放的性质,假设页表中的各页表项从内存地址为X的地方开始连续存放,每个页表项占3B且连续存放(只存储块号)则i号页表项的存放地址=X+3*i
页表中的也页号是隐藏的,不占用存储空间(类比数组下标)
页表记录的是块号,块号并非内存地址,J号内存块的起始地址=J*内存块大小
(块号是下图红色的二进制部分,而块内偏移则是黑色的)
地址的转换
虽然进程的各个页面是离散存放的,但是页面内部是连续存放的
如果要访问逻辑地址A,则需
①确定逻辑地址A对应的“页号”P
②找到P号页面在内存中的起始地址(需要查页表)
③确定逻辑地址A的“页内偏移量”W
逻辑地址A对应的物理地址=P号页面在内存中的起始地址+页内偏移量W
页号=逻辑地址/页面长度(取整数)
页内偏移量=逻辑地址%页面长度(取余数)
在计算机内部,地址是用二进制表示的如果页面大小刚好是2的整数幂,则计算机硬件可以很快速的把逻辑地址拆分成(页号,页内偏移量)
如果有K位表示“页内偏移量”,则说明该系统中一个页面的大小是
2
K
2^K
2K个内存单元
如果有M位表示“页号”,则说明在该系统中,一个进程最多允许有
2
M
2^M
2M个页面
显然页内偏移量位数可以和页面大小互推
基本地址变换机构
基本地址变换机构可以借助进程的页表将逻辑地址转换为物理地址。通常会在系统中设置一个页表寄存器(PTR, Page Table Register),存放页表在内存中的起始地址F和页表长度M。进程未执行时,页表的始址和页表长度放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把它们放到页表寄存器中。
页表长度M指的是对应进程的页表内有M个页表项
设页面大小为L,逻辑地址A到物理地址E的变换过程如下:
- 计算页号P和页内偏移量W(如果用十进制数手算,则P=A/L,W=A%L)
- 比较页号P和页表长度M,若P≥M,则产生越界中断,否则继续执行。(注意:页号是从0开始的,而页表长度至少是1,因此P=M时也会越界)
- 页表中页号P对应的页表项地址=页表起始地址F+页号P*页表项长度,取出该页表项内容b,即为内存块号。
- 计算E=b*L+W,用得到的物理地址E去访存(如果内存块号、页面偏移量是用二进制表示的,那么把二者拼接起来就是最终的物理地址了)
页表长度 | 页表项长度 | 页面大小 | |
---|---|---|---|
含义 | 页表中共有几个页表项(有几页) | 每个页表项占多大的存储空间 | 一个页面占多大的存储空间 |
页面大小 2 n 2^n 2n位,对应页内偏移量 n n n位
做题时不要忽略检查越界
页表的一些补充
假设某系统物理内存大小为4GB,页面大小为4KB,内存总共会被分为 2 32 / 2 12 = 2 20 2^{32}/ 2^{12}=2^{20} 232/212=220个内存块,因此内存块号的范围应该是 0 ∼ 2 20 − 1 0\sim 2^{20}-1 0∼220−1
因此至少要20个二进制位才能表示这么多的内存块号,由于空间是按字节分配的(不可能分配半个字节)因此至少要3个字节才够(每个字节8个二进制位,3个字节共24个二进制位)
各页表项会按顺序连续地存放在内存中,如果该页表在内存中存放的起始地址为X,则M号页对应的页表项是存放在内存地址为X+ 3*M
一个页面为4KB,则每个页框可以存放4096/3 = 1365个页表项,但是这个页框会剩余4096%3=1B页内碎片。
因此,1365号页表项存放的地址为X+3*1365+1
如果每个页表项占4字节,则每个页框刚好可存放1024个页表项
1024号页表项虽然是存放在下一个页框中的,但是它的地址依然可以用X+4*1024得出。
结论:理论上,页表项长度为3B即可表示内存块号的范围,但是,为了方便页表的查询,常常会让一个页表项占更多的字节,使得每个页面恰好可以装得下整数个页表项。
当然,做题不考虑这个,还是按3B走
具有快表的地址变换机构
基于局部性原理,,一般来说命中率能到90%以上
快表,又称联想寄存器(TLB,translation lookaside buffer ),是一种访问速度比内存快很多的高速缓存(TLB不是内存),用来存放最近访问的页表项的副本;由于访问快表速度比访存快,所以可以加速地址变换的速度。
TLB和普通Cache的区别:TLB中只有页表项的副本,而普通Cache中可能会有其他各种数据的副本
与此对应,内存中的页表常称为慢表。快表能存的少(cache本身就小嘛),存的是页表的一部分副本
进程切换时,快表内容一并清除
其实就是有地址变换需求时(当然,肯定先进行越界检查)在查慢表之前先看一下快表有没有,如果有就直接拿来用(命中就不用访存了),没有就查慢表,返回结果时顺手给快表中也复制过去一份。
时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)
空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的)
快表满了时,再加新项目肯定要替换,此处涉及替换算法