内存(二) - 页表与TLB

  • 作者: 雪山肥鱼
  • 时间:20210301 22:47
  • 目的:理解页表与TLB
# 1. Paging Introduction
  ## 1.1 简单举例
  ## 1.2 页表在哪里
  ## 1.3 页表里有什么
  ## 1.4 伪代码流程
# 2. Paging: Faster Translation
  ## 2.1 TLB基础算法
  ## 2.2 TLB 为什么这么快
  ## 2.3 谁来处理TLB Miss
  ## 2.4 TLB里有什么 
  ## 2.5 TLB遇到Context Switch
  ## 2.6 替换策略
  ## 2.7 真实的TLB Entry
# Paging: Smaller Tables
  ## 3.1 简单的解决方式:增加Page Size
  ## 3.2 页与Segment的混合方式
  ## 3.3 多级页表 multi-level page table

暂时替代虚拟内存分段的方式,我们将虚拟内存切割成固定的单元大小,将这些单元称为page。对应的在物理内存中相同大小的槽 - page frame 页帧。

1. Paging: Introduction

1.1 简单例子

假设有一个64bytes的地址空间,每一页为16bytes, 那么总共有4页,以及对应映射在物理内存中。


AS vs PS.png

上图可以看出:

  • 看似连续的地址空间,映射在物理空间中并不连续
  • OS 也会在物理空间占有一席

在一个完善的分页内存管理系统中

  • 更高效的支持抽象的地址空间,可以不必在意堆栈的增长方向与他们是如何使用的
  • 因为物理内存被分配成了固定大小,则减少外部碎片化,外部碎片化是因为分段式管理在物理内存层面上没有same units 的概念。

为了记录虚拟地址与物理地址的映射关系,所以才有了以per-process, 每个进程的为单位的 page table,也就是说一个进程,一个page table.(除了 inverted page table)

一个虚拟地址被分解成两部分

  1. the virtual page number(VPN)
  2. the offset 偏移

以上图为例,地址空间大小64字节。一个字节一个地址,2^6 = 64,所以地址式6位。page size = 16(2^4)byte,所以偏移量 有 4位:
在这个例子中page table 暂时理解为 简单存储了
VPN 0 -> PFN 3; VPN 1 -> PFN 7; VPN 2 -> PFN 5;VPN 3 -> PFN 2


虚拟地址的结构.png

假设举例,地址21(010101)

  • 前两位01 位 VPN,那么就是01 page.偏移量位 0101
  • 查page table 得01 page,对应物理内存页帧的位置(Physical frame number PFN)是07(11)
  • 07(11)与偏移地址组合 得到翻译后的物理地址
    如下图所示:


    Address Translation Process.png

    注:每一页都管理着若干内存。(此例为16个字节)

1.2 页表存在哪里

  • 页表大小计算
    以32位地址空间为里,4KB(2^12) 大小的 page size, 则有20位VPN.也就是说 页表一共要管理2^20 个 VPN,也就是1M个VPN,如果每个PTE(Page Table Entry) 有4个字节的大小,那么就是4M。
    如果OS中运行了100个程序,那么就要管理400M页表的大小。这是不行的。
    现在我们知道物理硬件MMU不可能做到这么大,那么把这400M大小的100个页表,放到内存中,又OS来管理。MMU 只保存 页表的地址。

1.3 页表里有什么

我们假设页表是线性页表,理解成一个数组,元素类型是physical address, 索引是VPN。比如虚拟地址的VPN 是 10,那么我们就在pagetable里面寻找第10个元素。那么就会寻找到这个虚拟地址的物理PFN。3
32位系统里,每一项PTE(page table entry)大小有4个字节。即32位,内容如下:


PTE structure.png

一些重要的位:

  • valid bit: 翻译后的地址 对于 这个程序是否是有效地址,比如进程访问的地址,翻译后发现是代码段,或者kernal的代码,那valid项必定是 0,必定会产生段错误
  • protection bits: read write execute 权限
  • present bit: 这个页是否存在内存,还是已经置换到了硬盘上,不在内存则会产生page fault 缺页,然后产生page 的 swapped in.
  • reference bit:一个页是否已经被访问过,which page are popular an d thus should be kept in memory. 对于页交换有用

1.4 伪代码流程

  VPN = (VirtualAddress & VPN_MASK) >> SHIFT
  PTEAddr = PTBR + (VPN * sizeof(PTE))
  // 1st access memory to fetch PTE
  PTE = AccessMemory(PTEAddr)
  
  if(PTE.Valid == False)
    RaiseException(SEGEMENTATION_FAULT)
  else if(CanAccess(PTE.ProtectBits) == False)
    RaiseException(PROTECTION_FAULT)
  else
    Offset = VirtualAddress & OFFSET_MASK
    PhysAddr = (PTE.PFT << PFN_SHIFT) | Offset
  // 2end access memory, fetch the specific content in PhysAddr
    Regsiter = AccessMemory(PhysAddr)
    

此时,引出两个问题

  1. 页表太大
  2. 两次访问内存,耗时。

2. Paging:Faster Translations(TLBs)

这里我们暂时解决在线性的内存表中访问两次内存,从而能造成耗时的问题。也就是说加速地址的翻译。

  • 借助硬件的帮忙
    TLB 是硬件MMU 的一部分,是一种cache,当然也可以叫做 address - translation cache.

2.1 TLB的基础算法

VPN = (VirtualAddress & VPN_MASK) >> SHIFT
(Success, TlbEntry) = TLB_Lookup(VPN)
if (Success == True) // TLB Hit
    if (CanAccess(TlbEntry.ProtectBits) == True)
        Offset = VirtualAddress & OFFSET_MASK
        PhysAddr = (TlbEntry.PFN << SHIFT) | Offset
        Register = AccessMemory(PhysAddr)
    else
        RaiseException(PROTECTION_FAULT)
 else // TLB Miss
    PTEAddr = PTBR + (VPN * sizeof(PTE))
    PTE = AccessMemory(PTEAddr)
    if (PTE.Valid == False)
      RaiseException(SEGMENTATION_FAULT)
    else if (CanAccess(PTE.ProtectBits) == False)
      RaiseException(PROTECTION_FAULT)
    else
       TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits)
       RetryInstruction()

2.2 TLB 为什么这么快

Example.png
int sum = 0;
for (i = 0; i < 10; i++) {
  sum += a[i];
}
  • 8 位的地址空间 外带16byte 的 页,也就是说8位现在被分成了4+4模式,4位vpn,4位页大小即offset.数组的类型位int型,即4个字节。假设a[0]处于上图位置,那么数组排布如上图所示。
    那么一组循环下来,TLB结果如下:
    miss->hit->hit->miss->hit->hit->hit->mis->hit->hit
    所以如果地址空间位数更多,页大小更大,那么只有第一次是miss,其他全是hit.大大提升访问速率。

2.3 谁来处理TLB Miss

硬件和OS一起接手管理TLB MISS.
Hardware处理方式:

  • 硬件需要知道page table 具体在哪里,通过MMU中的page table base register 即可。
  • 找到pagetable后,找到对应的PFN,计算出想要的physical address(intel x86 架构)
VPN = (VirtualAddress & VPN_MASK) >> SHIFT
(Success, TibEntry) = TLB_LookUp(VPN)
if (Success == True)
  if (CanAccess(TlbEntry.ProtectionBits) == True)
      Offset = VirtualAddress & OFFSET_MASK
      PhysAddr = (TlbEntry.PFN<<SHIFT) | Offset
      Register = AccessMemory(PhyAddr)
  else
    RaiseException(PROTECTION_FAULT)
 else  //TLB MISS
    RaiseException(TLB_MISS)
  1. TLB MISS, 指令流暂停,进入内核态,跳到trap handler.
  2. 针对 TLB MISS 的trap handler.寻找物理地址
  3. 更新 TLB,返回陷入trap的地方
  4. 从 trap 返回后,再次执行相同的指令,这里是和系统调用不同之处
  5. 同时OS要避免 TLB MISS 的无限递归
    • 处理trap handler 在物理内存中,这一块物理内存没有内存映射,目的也不是解决地址翻译。
    • reserver some entries in the TLB for permanently-valid translations, and use some of those permanent translation slots for handler code itself.TLB中的一些翻译槽就是用来hanlder codes的
  • CISC:Complex-instruction set computers
  • RISC:Reduced-instruction set computers

2.4 TLB里面有什么

TLB 的寻找机制是 parallel 的。


Entry in TLB.png
  • TLB 的 Valid BIT 和 Page table 的 Valide BIT 区别
    • Page Table 中 Entry 的 valid bit 代表当前的进程没有权限访问这一项,也就是说,这一项压根就没有分配给你。此时会产生段错误,进程被中止。
    • TLB:valid bit 表示:翻译地址是否有效。比如系统启动时,TLB里的每一项都是invalid,因为还并不存在寻找地址的动作。一旦虚拟内存启用,一个程序开始运行和开始访问虚拟空间时,TLB 才会 慢慢被填满。
    • TLB 的 valid位是很有用的,尤其是遇到上下文切换的。我们用这些来区分两个进程在TLB中的地址互补干涉。By setting all TLB entries to invalid, the system can ensure that the about-to-be-run process does not accidentally use a virtual-to-physical translation from a previous process.
  • 其他bit 大致相同

2.5 TLB遇到Context Switch

问题: TLB的Entry并不只属于当前正在跑的进程,当然包括其他进程。那么遇到上下文切换,应该如何处理呢才能保证进程隔离呢?


两个不同的Process.png

两个进程有相同的VPN 应该如何应对?

  • 每次切换进程都要flush TLB 的方式效率太低,开销太大
  • 在TLB中 增加 Address Space identifier(ASID) 项,类似每个进程的PID


    ASID.png

当然也会有两个进程VPN不同,PFN相同的情况,就是两个进程共享同一页的情况,比如共享库。这种情况会降低内存开销。

2.6 替换策略

LRU 策略 least-recently-used.最近最少使用的

2.7 真实的TLB Entry

TLB.png
  • 32位 4KB pagesize
  • 19 位虚拟地址,非20位原因,用户用到的地址,和 kernal用到的地址各占一半
  • G: global share ,公用的。此时ASID会失效
  • page mask:给多级页表用的。
  • MIPS 架构的TLB 有32项或者64项,但是其中会给OS保留一些,会有一个寄存器用来监控TLB,告诉OS,TLB现在保留了多少slots 给OS。
    • OS use these reserved mapping for code and data that it wants to access during critical times, where a TLB miss would be problematic.

3 Paging: Smaller Tables

TLB的线性表模式会导致TLB表太大了。每一个大概有4M,那么如果开了100个进程,那就会有400M。

3.1 简单的解决方式:增加Page Size

这种解决方式很明显会造成内存的内部碎片化,比如我扩展到了1M,宏观上看确实降低了页表的大小,但是,如果我只用其中的100个字节。那么内部碎片化的问题就会出现。

3.2 页与Segment的混合方式

假设有地址空间大小16KB, 页大小1KB


图片.png

图片.png

这个思路是有三张页表,code heap stack各一张page table.每张表依旧有base/bounds寄存器限制每个段的大小。
base寄存器指向的是页表的物理地址


hybird virtual address.png
  • 但是这种混动方式依旧有缺陷,段的管理方式并不灵活,尤其对于松散的堆管理。
  • 也会造成外部碎片,寻找free space 变得更加复杂

3.3 多级页表 multi-level page table

基本原理:

  1. 讲页表砍碎,每一块和page size 相同。
  2. 如果页表(be chopped up)中的一页中所管理的,每一项entry(VPN<->PFN)都是invalid,则这一页不会被分配内存。
  3. 页目录(Page directory)的引入
    页目录告诉你了,页表的每一页在哪里。
    举例:page size: 16个字节,地址空间16位。则页表总共有16项:


    线性表与多级列表的区别.png
  • 左:线性表,浪费
  • 右:参照左,每四组是一个页,其中第2页,第3页的valid选项全部位 0 ,所以不用分配,如果按照页目录来看,只用分配第一项和第四项,即对应physical address 里 第201page frame,和204 page frame。PDE(Page Directoryt Entry)
    a). 带有页目录的地址分解:
    举例:16KB地址空间(14 bits),page size:64bytes(6 bits), VPNS(8 bits)
    所以对于页表来说共有2^8entrys需要管理。


    图片.png

    此时 页表的大小位2^8 * 4(每个entry 4个字节),那么此时讲page table 切碎,每个碎片式page size 大小,那么就要除6:
    2^8 * 4 / 2^6 = 2 ^ 4.
    所以页目录共管理2^4 page,如图所示:


    地址结构.png
  • 这就非常明显了,虚拟地址出来后,先找计算属于页目录中的哪一项(即对应的 physical address 的 slot,即这个页表的PFN)
    PDEAddr = PageDirBase + (PDIndex + sizeof(PDE))
  • 找到在对应page table 中的第几项,
  • 在talbe 的 <VPN, PFN>中,找到PFN,得到最后的地址


    举例.png

    例:11 1111 1000 000
    页目录:11 11 :15,那么就是页目录管理的第15个页表
    页表Index:1110: 14,那么就是这张页表的 第14项
    PFN:得到PFN是55,最终地址:00 1101 1100 0000 = 0下DC0.

超过两级的多级列表,实际上就是页目录上面还有一层管理页目录的页目录。原理是一致的。

代码:

VPN = (VirtualAddress & VPN_MASK) >> SHIFT
(Success, TlbEntry) = TLB_Lookup(VPN)
if (Success == True) // TLB Hit
    if(CanAccess(TlbEntry.ProtectionBits  == True)
          Offset = VirtualAddress & OFFSET_MASK
          PhyAddr = (TlbEntry.PFN<<SHIFT) | Offset
          Regsiter = AccessMemoryt(PhyAddr) //PhyAddr
    else
          RaiseException(Protection_Fault)
else
    // first get page directory entry
    PDIndex = (VPN & PD_MASK) >> PD_SHIFT
    PDEAddr = PDBR + (PDIndex * sizeof(PDE))
    PDE = AccessMemory(PDEAddr) //PDEAddr
    if(PDE.Valid == False)
          RaiseException(Segmentation_Fault)
    else
        // PDE is valid:now fetch pte from page table
        PTIndex = (VPN & PT_MASK) >> PT_SHIFT
        PTEAddr = ((PDE.PFN) << SHIFT) + (PTEIndex * sizeof(PTE))
        PTE = AccessMemeory(PTEAddr)  //PTEAddr
        if(PTE.Valid == False)
            RaiseException(Segmentation_Fault)
        else if (CanAccess(PTE.ProtectionBits)== False)
            RaiseException(Protection_Fault)
         else
            TLB_INSERT(VPN, PTE.PFN, PTE.ProtectionBits)
            RetryInstruction()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容