在启动分页机制时需要用到页表,页表保存的是虚拟页号与物理页框之间的映射关系,其中页表项与虚拟内存页有一一对应的关系,当虚拟内存地址空间过大时页表项会占用过多内存(即使采用大页面,该问题也不能得到缓解)。

考虑一个例子,虚拟地址空间为64位,页面大小为4KB,页表项大小为4Bytes,物理内存大小为512MB(参考【1】),如果采用单层页表计算可以得到页表项的数量为$2^{64-12} = 2^{52}$,页表项占用的内存大小为$2^{54}$Byte。

显然上述情况下单层页表的实现方式是不现实的,采用多级页表倒排页表可以解决页表项占用过多内存的问题。在应用多级页表进行地址转换时,每级页表负责若干位的地址转换,可以显著减少页表项个数,但一次地址转换需要多次页表查询操作。倒排页表,顾名思义,它与常规页表相反,存储的是有关每个物理页框的信息,所以倒排页表项与物理内存页框有一一对应关系,它所包含的表项数量较少(物理内存大小一般远小于虚拟内存大小)。

无论是何种页表,它的功能总是将虚拟地址转换为物理地址。系统出于对多进程的支持,实际转换关系是 进程号(process id, PID) + 虚拟页号(virtual page number, VPN) + 页内偏移(offset)---> 物理页框(physical page number,PPN) + 页内偏移(offset),如下所示。

常见的倒排页表组织形式有线性倒排页表散列倒排列表,下面分别从内存占用和地址转换效率两个方面来评价这两种方式。

1. 线性倒排页表

线性倒排页表是倒排页表的基本形式,由于它是全局唯一的,并且每个进程有自己独立的地址空间,表项中必须包含进程ID。表项由三部分组成,进程ID(PID,16位),虚拟页号(VPN,52位),信息位(INFO,12位,包含该页的一些保护信息),共80位(10Bytes)。物理页框号由表项索引隐含表示。还是考虑上面的例子(物理内存大小为512MB),所有表项占用的内存大小为10 X $2^{29 - 12}$ Bytes = 10 X 128KB = 1.3MB。转换过程如下图。

尽管页表的大小已经很小了,但是一次地址转换所需的内存查询操作次数却很多。为了找到PID和VPN的匹配对,每次转换需要128K次的内存访问操作。这个PID和VPN的搜索过程导致地址转换十分低效,可以用散列表降低内存访问次数

2. 散列倒排页表

为了加快地址转换速度,可以在线性转换表前增加一层散列表。散列表的输入是PID和VPN,输出是倒排页表的索引。利用散列表进行散列时可能发生冲突,可以利用链地址法解决冲突,我们通过在倒排页表项中增加next域使其能够构成链表(表头的索引位于散列表中)。转换过程如下图。

图中蓝色部分是相比于原线性倒排页表增加的部分。将原PID(0x0)和VPN(0x1)进行散列计算后,查找到对应的倒表页表索引为0x0,而倒排页表项0x0中的PID(0x1)和VPN(0xA63)与原PID和VPN不一致,说明散列发生冲突,顺着链表查询下一个页表项0x18F1B,该项的PID和VPN与原PID和VPN匹配,成功查找到了物理页框号。

散列倒排页表的大小为 hash表大小 + 倒排页表大小 = 4 X 128KB + 14 X 128KB = 2.3MB,理想情况下(找到一个足够好的散列函数),平均一次地址转换需要2.5次内存访问操作。

3. 总结

  1. 优点

    减少占用的内存空间

  2. 缺点

    更长的查询时间

    进程间共享内存实现更困难

4. 参考

  1. Topics: Inverted Page Tables, TLBs
  2. Inverted Page Table in Operating System

17610101873
3 声望1 粉丝