基本分页存储管理

假设是按字节编址

连续分配方式的缺点

考虑支持多道程序的两种连续分配方式

  1. 固定分区分配:缺乏灵活性,会产生大量的内部碎片,内存的利用率很低
  2. 动态分区分配:会产生很多外部碎片,虽然可以用“紧凑技术”处理,但是处理时间代价很高

原因:连续分配要求进程占有的必须是一块连续的内存区域
能否讲一个进程分散地装入到许多不相邻的分区,便可充分利用内存

基本分页存储管理的思想:把内存分为一个个相等的小分区,再按照分区大小把进程拆分成一个个小部分

分页存储管理的基本概念

页框/页帧:内存空间分成的一个个大小相等的分区(比如4KB)
页框号:页框的编号,从0开始,从低地址开始

页/页面:用户进程的地址空间分为和页框大小相等的一个个区域
页号:页/页面的编号,从0开始

进程的最后一个页面可能没有一个页框那么大,页框不能太大,否则可能产生过大的内部碎片

操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中,也就是说,进程的页面与内存的页框有一一对应的关系
每个页面不必连续存放,也不必按照先后顺序,可以放到不相邻的各个页框中

如何实现逻辑地址到物理地址的转换

进程在内存中连续存放时,通过动态重定位实现逻辑地址到物理地址的转换。在装入模块之后,内存中指令使用的依然是逻辑地址,直到指令执行的时候才会进行地址转换。系统会设置一个重定位寄存器,用来存放装入模块存放的起始位置,重定位寄存器中的值加上逻辑地址就是该逻辑地址实际对应的物理地址

如果采用分页技术

  1. 算出逻辑地址对应的页号。页号 = 逻辑地址/页面长度
  2. 该页号对应页面在内存中的起始地址。操作系统会使用数据结构记录进程某个页面的起始地址
  3. 逻辑地址在页面中的偏移量。页内偏移量 = 逻辑地址%页面长度
  4. 物理地址 = 页面地址 + 页内偏移量

页框大小为4KB,地址空间为4GB的系统
页号为前20位,页内偏移量为后12位

页表:为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表

一个进程对应一张页表
进程的每一页对应一个页表项
每个页表项由页号和页框号组成
页表记录进程页面和实际存放的页框之间的对应关系

每个页表项的长度是相同的,页号是隐含的
各页表项会按顺序连续存放在内存中,如果该页表在内存中的起始地址是X,4GB/4KB系统的页框有

个,需要至少三个字节才够,所以M号页对应的页表项在X+3M的位置
如果进程有n个页面,进程的页表总共占3n个字节
因此只需要知道页表存放起始地址和页表项长度,就可以找到各个页号对应的页表项存放的位置

基本地址变换机构

用于实现逻辑地址到物理地址转换的一组硬件机构

通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F和页表长度M(M个页表项)
进程未执行时,页表的起始地址和页表长度放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把他们放到页表寄存器中

  1. 根据逻辑地址A计算出页号P和页内偏移量W(如果是十进制给出,取商、取模)
  2. 根据页表寄存器中的页表长度检查页号是否合法,不合法(P≥M)抛出越界中断
  3. 查询页表,找到页号对应的页表项,确定页面存放的页框号(页表起始地址+页号*页表项长度)
  4. 用页框号和页内偏移量得到物理地址
  5. 访问物理地址

例子:
若页面大小L为1KB,页号2对应的内存块号b = 8,将逻辑地址A = 2500转换为物理地址E
等价描述:某系统按字节寻址,逻辑地址结构中,页内偏移量占10位,页号2对应的内存块号b = 8,将逻辑地址A = 2500转换为物理地址E

页号和页内偏移量:p = A/L = 2500/1024 = 2;w = A%L = 2500%1024 = 452
没有越界,页号2的页框号为b = 8
物理地址E = b * L + w = 8 * 1024 + 452 = 8644

基本分页存储管理中地址是一维的,即只要给出一个逻辑地址,系统就可以自动计算出页号、偏移量,不需要显式告诉系统偏移量是多少

理论上,页表项长度为3即可表示内存块号的范围,但是为了方便页表查询,会让页面恰好能装得下整数个页表项,令每个页表项占4字节
4KB页面,可以放4096/3 =1365个页表项,有4096%3 =1B的碎片,访问1365及之后的页表项时,还要考虑前面的页框中的碎片,才能得到页表项的物理地址,比较麻烦

进程页表通常存放在连续的页框中,这样就能用统一的计算方式得到想要得到的页表项存储的位置

地址变换过程中有两次访存操作:查询页表、访问目标内存单元

具有快表的地址变换机构

局部性原理

int i = 0;
int a[100];
while(i < 100){
    a[i] = i;
    i++;
}

如果这个程序将程序对应的指令存放在10号内存块,将程序中定义的变量存放在23号内存块,当这个程序执行时,会很频繁地反问10、23号内存块

时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能被再次执行;如果某个数据被访问过,不久之后该数据很有可能再次被访问(因为程序存在大量循环)
空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问(因为很多数据在内存中连续存放)

基本地址变换机构中,每次要访问一个逻辑地址,都要查询页表,由于局部性原理,可能连续多次查询同一个页表项

快表:又称联想寄存器(TLB),是一种访问速度比内存块很多的高速缓存,用来存放当前访问的若干页表项,以加速地址变换的过程。内存中的页表常称为慢表

引入快表后地址的变换过程

  1. CPU给出逻辑地址,由某个硬件计算出页号、页内偏移量,将页号与快表中的所有页号比较
  2. 如果找到匹配的页号,说明要访问的页表项在快表中有副本,直接从快表中取出该页对应的内存块号,再将内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此如果快表命中,访问某个逻辑地址仅需一次访存
  3. 如果没有找到匹配的页号,需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,将内存块号和页内偏移量拼接形成物理地址,访问物理地址对应的存储单元;找到页表项后,同时也会将该页表项存入快表,若快表已满,会按照一定的算法对旧的页表项进行替换。因此如果快表未命中,访问某个逻辑地址需要两次访存

一般来说,快表的命中率可以达到90%以上

例子:
某系统使用基本分页存储,采用具有快表的地址变换机构,访问一次快表耗时1us,访问一次内存耗时100us,若快表的命中率为90%,那么访问一个逻辑地址的平均耗时是多少?

有的系统支持快慢表同时查询

多级页表

单级页表存在的问题

  1. 页表必须连续存放,因此当页表很大时,需要占用很多个连续的页框
  2. 没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面(局部性原理)

对问题1

可将页表进行分组,使每个内存块刚好可以放入一个分组。为离散分配的页表再建立一张页表,称为页目录表,或外层页表
各级页表的大小不能超过一个页面

例子:
某系统按字节编址,采用40位逻辑地址,页面大小为4KB,需要采用几级页表,页内偏移量是多少位?

页框总数为

,需要
位来索引页框号,
,所以一个页表项占
字节。一个页框能够存放
个页表项,所以各级页表最多包含
个页表项,需要
个二进制位才能映射到
个页表项,因此每级页表对应页号为
位,
位的页号需要至少分为

针对两级页表

  1. 按照地址结构将逻辑地址拆分为三部分:一级页号、二级页号、页内偏移量
  2. 从PCB中读出页目录表起始地址,再根据一级页号查找页目录表,找到下一级页表在内存中的位置
  3. 根据二级页号查表,找到最终想访问的内存块号
  4. 结合页内偏移量得到物理地址

对问题2

可以在需要访问页面时,才把页面调入内存(虚拟存储技术),可以在页表项中增加一个标志位,用于表示该页面是否已经调入内存
若想访问的页面不在内存中,会产生缺页中断(内中断),然后将目标页面从外存调入内存
之后的文章会有展开

两级页表访存次数分析:如果没有TLB,第一次访存是访问内存中的页目录表,第二次访存是访问内存中的二级页表,第三次访存是访问目标内存单元

你可能感兴趣的:(基本分页存储管理)