• 【OSTEP】分页: 较小的表 | 分页和分段 | 时空折中 | 多级页表 | 反向页表


    本系列博客为复习操作系统导论的笔记,内容主要参考自:

    • Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau, Operating Systems: Three Easy PiecesA. Silberschatz, P. Galvin, and G. Gagne,
    • Operating System Concepts, 9th Edition, John Wiley & Sons, Inc., 2014, ISBN 978-1-118-09375-7.Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

    目录

    0x00 引入:页表太大怎么办

    0x01 试试使用更大的页?

    0x01 混合方法:分页和分段

    0x02 多级页表(Multi-level Page Tables)

    0x03 例子:单级页表

    0x04 例子:二级页表

    0x05 三级页表(Three-level Page Table)

    0x06 反向页表(Inverted Page Table)


    0x00 引入:页表太大怎么办

    我们现在来解决分页的第二个问题 —— 页表太大!

    我们通常为系统中的每个进程设置一个页表,假设32位地址空间有4KB的页和4字节的页表项。

    页表大小为: \frac{2^{32}}{2^{12}} \, *\, 4\, \textrm{Byte }= 4\, \textrm{MByte} 

    Page table are too big and thus consume too much memory.

    0x01 试试使用更大的页?

    ❓ 简单的解决方案:如果我们使用更大的页呢?

    💡 假设32位地址空间有 16KB 页和 4 字节的页表项。

    页表大小为:   \frac{2^{32}}{2^{14}}\, *\, 4 = 1\textrm{MByte} \, \, \,\textrm{ per page table}

    然而,这种方法的问题在于,大内存页会导致每页内的浪费!

    因为浪费问题存在于分配单元的内部,所以这被称为 "内部碎片问题"(internal fragmentation),

    因此,结果是应用程序回分配页,但只用每页的一小部分,而内存就会充满这些过大的页。

    这未免有些太奢侈了哈,就像一道菜只吃两口就扔了一样,这很浪费的说……

     Big pages lead to internal fragmentation.

    Most of the page table is unused, full of invalid entries!

    0x01 混合方法:分页和分段

    Page table for each segment

    • The base register for each of these segments contains the physical address of the page table of that segment.
    • The bound register: indicate the end of the page table (# of valid entries).

    例子:每个进程有3个与之相关的页表

    Address translation

    • The hardware uses the segment bits (SN) to determine which base and bounds pair to use.
    • The hardware then takes the physical address of the page table and combines it with the VPN as follows to form the address of the page table

    硬件使用段位(SN)来决定使用哪一对基数和边界。
    然后,硬件将页表的物理地址与VPN结合,如下所示形成页表的地址:

    1. 01: SN = (VirtualAddress & SEG_MASK) >> SN_SHIFT
    2. 02: VPN = (VirtualAddress & VPN_MASK) >> VPN_SHIFT
    3. 03: AddressOfPTE = Base[SN] + (VPN * sizeof(PTE))

    遗憾的是,这种方法并非十全十美。首先,它仍然要使用分段。正如我们讨论的那样,分段并不像我们需要的那要灵活,因为他假定地址空间有一定的使用模式。例如,如果有一个大而稀疏的堆,仍然可能导致大量的页表浪费。其次,这种混合导致外部碎片再次出现。

    0x02 多级页表(Multi-level Page Tables)

    来大哥了,既然前面介绍的两个都挺摆烂的,这个多级页表可能会让你眼前一亮。

    ❓ 思考:如何摆脱页表中所有这些无效的区域,而不是将它们全部保留在内存中?而不是把它们全部保留在内存中?

    💡 把线性页表变成像树一样的玩意!

    • Chop up the page table into page-sized units.  把线性页面表变成类似树的东西。
    • If an entire page of page-table entries is invalid, don’t allocate that page of the page table at all.  如果一整页的页表项是无效的,就根本不要分配页表的那一页。
    • To track whether a page of the page table is valid, use a new structure, called page directory.   为了跟踪页表的某一页是否有效,使用一个新的结构,称为页目录。
    • The page directory contains one entry per page of the page table.   页目录 包含页表的每一页的一个项。
    • It consists of a number of page directory entries (PDE).   它由一些 页目录项(PDE)组成。
    • PDE has a valid bit and page frame number (PFN).   PDE有一个有效的位和 页帧号(PFN)

    优点:

    • Only allocates page-table space in proportion to the amount of address space you are using.  只按照你所使用的地址空间的比例分配页表空间 
    • The OS can grab the next free page when it needs to allocate or grow a page table.  当操作系统需要分配或增长页表时,它可以抓取下一个空闲页。

    缺陷:

    • Multi-level table is a small example of a time-space trade-off  (时空折中).
      • On a TLB miss, two loads from memory will be required to get the right translation information from the page table.   在TLB缺失时,需要从内存中加载两次,以便从页表中获得正确的翻译信息。
      • On a TLB hit, performance is obviously identical.   在TLB击中时,性能显然是相同的。
    • Complexity (复杂).

    理解时空折中

    在构建数据结构时,应始终考虑时间和空间的折中(time-space trade-off)。通常,如果你希望更快地访问特定的数据结构,就必须为该结构付出空间的代价。(正所谓以时间换空间)

    0x03 例子:单级页表

    • 页表项:2^8=256 项
    • 页表大小:256*4\textrm{ Byte} = 1\textrm{Kbyte}

     

    0x04 例子:二级页表

    Chop up the page table into page-sized units and create a page directory.

    If an entire page of page-table entries is invalid, don’t allocate that page of the page table at all.

    • 访问无效时会抛出一个异常

    页目录(Page directory):

    • 由 16 个项组成 → 每页页表有一个项(即页表的PFN)。
    • 需要 16*4 字节 = 64字节 → 可以装入一个页面。
    • 需要 4 bits的页目录索引 → 用于查找页表项的地址。

    二级页表寻址(Addressing):

    页目录索引(PDIndex)

    它用于从VPN中找到页面目录条目(PDE)的地址。

    PDEAddr = PageDirBase + (PDIndex * sizeof(PDE))

    页表索引 (PTIndex)

    它用于索引页表本身,给我们的 PTE 的地址。

    PTEAddr = (PDE.PFN << SHIFT) + (PTIndex * sizeof(PTE))
    PhysAddr = (PTE.PFN << SHIFT) + offset

    二级页表 - 详细的内存视图:

     

    0x05 三级页表(Three-level Page Table)

    Make each piece of the page table and page directory fit within a page !

    ❓ 一级两级三级……我们到底需要多少级?

    单个页面中的 PTE 数量 ( 512/4 = 128 (2^7)  ) → 页表索引(7 bit)。

    页目录索引需要 14 位(2^{14}个项目 - 2^7 个页)→ 太大!

    页目录:2^{14} / 2^7 = 2^7 页目录中的条目 → 适合于一个页面内的项!

    我们需要三级!

     三级页表的例子:

    多级页表控制流程 - TLB命中:

    1. VPN = (VirtualAddress & VPN_MASK) >> SHIFT
    2. (Success,TlbEntry) = TLB_Lookup(VPN)
    3. if ( Success == True ) // TLB Hit
    4. if ( CanAccess(TlbEntry.ProtectBits) == True )
    5. Offset = VirtualAddress & OFFSET_MASK
    6. PhysAddr = (TlbEntry.PFN << SHIFT) | Offset
    7. Register = AccessMemory(PhysAddr)
    8. else
    9. RaiseException(PROTECTION_FAULT);
    10. else
    11. // TLB Miss : perform the full multi-level lookup

    多级页表控制流程 - TLB未命中:

    1. else // perform the full multi-level lookup
    2. PDIndex = (VPN & PD_MASK) >> PD_SHIFT
    3. PDEAddr = PDBR + (PDIndex * sizeof(PDE))
    4. PDE = AccessMemory(PDEAddr) // fetch PDE from PD
    5. if ( PDE.Valid == False ) RaiseException(SEGMENTATION_FAULT)
    6. else // PDE is Valid
    7. PTIndex = (VPN & PT_MASK) >> PT_SHIFT
    8. PTEAddr = (PDE.PFN << SHIFT) + (PTIndex * sizeof(PTE))
    9. PTE = AccessMemory(PTEAddr) // fetch PTE from PT
    10. if ( PTE.Valid == False )
    11. RaiseException(SEGMENTATION_FAULT)
    12. else if ( CanAccess(PTE.ProtectBits) == False )
    13. RaiseException(PROTECTION_FAULT);
    14. else // now refresh TLB and restart
    15. TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits)
    16. RetryInstruction()

    练习:

    0x06 反向页表(Inverted Page Table)

      "生灵有倒悬之急"

    One entry for each real page of memory.

    每个表项由存储在该真实内存位置的页面的虚拟地址组成,并附有关于拥有该页面的进程的信息(即pid或asid)。

    减少了存储每个页表所需的内存,但增加了在发生页引用时搜索表所需的时间。

    使用哈希表将搜索限制在一个或最多几个(例如64位 UltraSPARC 和 PowerPC)。

     

    1. 📌 [ 笔者 ]   王亦优
    2. 📃 [ 更新 ]   2022.11.8
    3. ❌ [ 勘误 ]   /* 暂无 */
    4. 📜 [ 声明 ]   由于作者水平有限,本文有错误和不准确之处在所难免,
    5. 本人也很想知道这些错误,恳望读者批评指正!

    📜 参考资料 

    Remzi H. Arpaci-Dusseau and Andrea C. Arpaci-Dusseau, Operating Systems: Three Easy Pieces

    A. Silberschatz, P. Galvin, and G. Gagne,

    Operating System Concepts, 9th Edition, John Wiley & Sons, Inc., 2014, ISBN 978-1-118-09375-7.

    Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

    百度百科[EB/OL]. []. https://baike.baidu.com/.

  • 相关阅读:
    力扣第45题 跳跃游戏II c++ 贪心算法
    前端面试题之CSS篇
    hot100- 最小栈
    持续测试简介
    MySql5.1+版本主从同步配置(bin_log)模式
    超越openmp通用核心的硬件
    面向万物智联的语义通信网络
    BGP联邦实验
    视频评价工具AVQT介绍
    金仓数据库KingbaseES客户端应用参考手册--7. sys_basebackup
  • 原文地址:https://blog.csdn.net/weixin_50502862/article/details/127742274