侧边栏壁纸
博主头像
landery博主等级

行李箱里装不下我想去的远方

  • 累计撰写 45 篇文章
  • 累计创建 26 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

云计算_03_虚拟化技术_内存虚拟化

landery
2022-04-25 / 0 评论 / 0 点赞 / 74 阅读 / 5,541 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-05,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1 内存虚拟化

物理机的内存是一段连续分配的地址空间,VMM上层的各个虚拟机共享物理机的物理内存地址空间。由于虚拟机对于内存的访问是随机的,并且又需要保证虚拟机内部的内存地址是连续的,因此VMM就需要合理映射虚拟机内部看到的内存地址到物理机上的真实内存地址。

2 操作系统地址转换

再说虚拟机内存地址转换之前,我们先讨论一下,宿主机上操作系统的地址转换。

为什么在操作系统中不直接使用物理地址,而使用虚拟地址?

因为使用虚拟地址可以带来诸多好处:

  1. 在支持多进程的系统中,如果各个进程的镜像文件都使用物理地址,则在加载到同一物理内存空间的时候,可能发生冲突。
  2. 直接使用物理地址,不便于进行进程地址空间的隔离。
  3. 物理内存是有限的,在物理内存整体吃紧的时候,可以让多个进程通过分时复用的方法共享一个物理页面(某个进程需要保存的内容可以暂时swap到外部的disk/flash),这有点类似于多线程分时复用共享CPU的方式。

既然使用虚拟地址,就涉及到将虚拟地址转换为物理地址的过程,这需要MMU(Memory Management Unit)和页表(page table)的共同参与。在这里就不阐述了,具体的可以查看这篇文章:虚拟地址转换[一] - 基本流程 - 知乎 (zhihu.com)

反正我们只要记住,虚拟地址到物理地址的转换需要操作系统完成。

这是传统虚拟地址到物理地址转换的过程。

这里需要简单了解一下TLB。为了减少访问内存次数,一般查找页表时会先去查找TLB,它是一个硬件缓存。

因为访问内存中的页表相对耗时,尤其是在现在普遍使用多级页表的情况下,需要多次的内存访问,为了加快访问速度,系统设计人员为page table设计了一个硬件缓存 - TLB ,CPU会首先在TLB中查找,因为在TLB中找起来很快。TLB之所以快,一是因为它含有的entries的数目较少,二是TLB是集成进CPU的,它几乎可以按照CPU的速度运行。

3 虚拟机内存地址转换

虚拟机中存在一个Guest OS,虚拟机之中的应用程序使用的是虚拟地址,该地址我们称为GVA(Guest Virtual Address),经过Guest OS地址转换后变成的中间的物理地址,我们称为GPA(Guest Physical Address),然后这个物理地址对于VMM来说,依然是虚拟地址,需要再一次进行地址转换,最终转换后的真实内存物理地址,我们称为HPA(Host Physical Address)。

image.png

从下图,可以清晰看出地址转换的过程,可以看到相较于传统系统,需要进行两次地址转换。

image.png

那么如何实现呢?

4 软件实现-影子页表

为了支持GVA->GPA->HPA的两次转换,可以计算出GVA->HPA的映射关系,将其写入一个单独的影子页表(sPT - shadow Page Table)。在一个运行Linux的guest VM中,每个进程有一个由内核维护的页表,用于GVA->GPA的转换,这里我们把它称作gPT (guest Page Table)。

VMM层的软件会将gPT本身使用的物理页面设为write protected的,那么每当gPT有变动的时候(比如添加或删除了一个页表项),就会产生被VMM截获的page fault异常,之后VMM需要重新计算GVA->HPA的映射,更改sPT中对应的页表项。可见,这种纯软件的方法虽然能够解决问题,但是其存在两个缺点:

  • 实现较为复杂,需要为每个guest VM中的每个进程的gPT都维护一个对应的sPT,增加了内存的开销。
  • VMM使用的截获方法增多了page fault和trap/vm-exit的数量,加重了CPU的负担。

在一些场景下,这种影子页表机制造成的开销可以占到整个VMM软件负载的75%。

虚拟CR3和物理CR3

  • 虚拟CR3:保存客户机页表的基地址。
  • 物理CR3:保存影子页表的宿主机物理基地址。

5 硬件辅助-EPT/NPT

为什么需要硬件辅助的内存虚拟化?

传统的IA32架构,从硬件上只支持一次地址转换,导致单纯的软件虚拟化方法存在种种问题,例如实现复杂,内存开销大,CPU开销大,TLB性能低下。通过在CPU体系架构上增加相应的硬件支持,可以彻底解决这些问题。如模拟器使用的HAXM,KVM。

为此,各大CPU厂商相继推出了硬件辅助的内存虚拟化技术,比如Intel的EPT(Extended Page Table)和AMD的NPT(Nested Page Table),它们都能够从硬件上同时支持GVA->GPA和GPA->HPA的地址转换的技术。

GVA->GPA的转换依然是通过查找gPT 页表完成的,而GPA->HPA的转换则通过查找nPT 页表来实现,每个guest VM有一个由VMM维护的nPT。其实,EPT/NPT就是一种扩展的MMU(以下称EPT/NPT MMU),它可以交叉地查找gPT和nPT两个页表:

假设gPT和nPT都是4级页表,那么EPT/NPT MMU完成一次地址转换的过程是这样的(不考虑TLB):

首先它会查找guest VM中CR3寄存器(gCR3)指向的PML4页表,由于gCR3中存储的地址是GPA,因此CPU需要查找nPT来获取gCR3的GPA对应的HPA。这里我们称一次nPT的查找过程为一次nested walk

如果在nPT中没有找到,则产生EPT violation异常(可理解为VMM层的page fault)。如果找到了,也就是获得了PML4页表的物理地址后,就可以用GVA中的bit位子集作为PML4页表的索引,得到PDPE页表的GPA。接下来又是通过一次nested walk进行PDPE页表的GPA->HPA转换,然后重复上述过程,依次查找PD和PE页表,最终获得该GVA对应的HPA。

不同于影子页表是一个进程需要一个sPT,EPT/NPT MMU解耦了GVA->GPA转换和GPA->HPA转换之间的依赖关系,一个VM只需要一个nPT,减少了内存开销。如果guest VM中发生了page fault,可直接由guest OS处理,不会产生vm-exit,减少了CPU的开销。可以说,EPT/NPT MMU这种硬件辅助的内存虚拟化技术解决了纯软件实现存在的两个问题。

EPT/NPT MMU优化

EPT TLB:EPT TLB存储的是GVA->HPA的映射,EPT MMU在查找GPT和EPT之前,会先去查找自己的EPT TLB是否存在(GVA->HPA)映射(前面为了描述的方便省略了这一步), 没有则查找GPT和EPT页表,还是没有CPU则抛出EPT Violation异常由VMM来处理(产生VM-Exit)。

1、 TLB优化一:通过PCID/ASID区分同一VM内不同的进程提高进程切换的效率

  • 原因: 不能区分一个TLB表项属于客户机内哪个进程,所以每次进程切换时,为避免不同进程间TLB混用,CPU会强制TLB全部失效。
  • 解决方法:同一VM内不同的进程可能会有相同的GVA,为了避免进程切换的时候flush刷新所有的TLB,可通过给TLB entry加上一个标识进程的tag来区分,这个tag标志在x86体系中则被叫做PCID,在ARM体系中被叫做ASID。
  • 原理:通过在每个TLB entry(GVA->HPA)上增加一个标志PCID,标识并区分来自不同的进程,利用PCID可以区分一个TLB entry属于哪个进程。CR3寄存器存储了当前进程对应的PCID,CR3中的PCID只占12个bits,最多能表达4096个process,这样虚拟机内部的进程切换不需要刷新TLB。
  • 意义:硬件级的对TLB资源管理的优化,硬件具备了区分不同的TLB entry属于不同进程的能力,避免了在每次进程切换时,使全部TLB失效,提高了进程切换的效率。

2、TLB优化二:通过VPID/VMID区分不同的VCPUs和宿主机(VMM),提高VM切换的效率

  • 背景:不能区分一个TLB表项属于哪个客户机VCPU或VMM,所以每次VM-Exit和VM-Entry,为避免VMM以及不同虚拟机间TLB混用,CPU会强制TLB全部失效。

  • 解决方法:不同的VM内的进程会有相同的GVA,VM和宿主机(VMM)也会有相同的VA,为了避免VM和宿主机(VMM)切换的时候flush刷新所有的TLB,可通过给每个TLB加上一个标识VM与VMM的tag来区分,这个tag标志在x86体系中则被叫做VPID,在ARM体系中被叫做VMID。

  • 原理

    • 通过在每个TLB上增加一个标志VPID,标识并区分来自不同的VCPU或VMM。每个TLB表项与一个VPID相关联,用于唯一标识一个VCPU或VMM,利用VPID可以区分一个TLB表项属于哪个VCPU或VMM。(VMM的VPID为0,每个VCPU也各对应一个VPID。)
    • 当进行虚拟地址到物理地址转换的时候,只有一个TLB表项对应的VPID与当前正在运行的虚拟机的VCPU的VPID相同的时候,才可以用该TLB表项把虚拟地址转换为物理地址。
  • 意义:硬件级的对TLB资源管理的优化,硬件具备了区分不同的TLB项属于不同虚拟处理器地址空间的能力,避免了在每次VM-Exit和VM-Entry时,使全部TLB失效,提高了VM切换的效率。

3、优化三、减少内存访问次数

背景:以上述例子为例,假设客户机页表和EPT扩展页表都是4级页表,在最坏的情况下(也就是TLB一次也没有命中),gPT中的每一级转换都需要一次nested walk,而每次nested walk需要4次内存访问,因此5次nested walk总共需要 (4+1)*5-1 = 24 次内存访问(就像一个5x5的二维矩阵一样):

preview

虽然这24次内存访问都是由硬件自动完成的,不需要软件的参与,但是内存访问的速度毕竟不能与CPU的运行速度同日而语,而且内存访问还涉及到对总线的争夺,次数自然是越少越好。

解决:要想减少内存访问次数,要么是增大EPT/NPT TLB的容量,增加TLB的命中率,要么是减少gPT和nPT的级数。

减少级数,需要采用大页(large page)/巨页(huge page)技术:减少EPT的级数(空间换时间)

4、自伸缩内存调节技术:通过气球(balloon)回收或分配虚拟机内存

自伸缩内存调节技术:一个guest VM在创建的时候就获得了VMM分配给它的一定大小的宿主机物理内存,VMM通过“气球(balloon)”诱导客户机操作系统来回收或分配客户机所拥有的宿主机物理内存。

  • 原理:

    • 气球膨胀(balloon inflation):当VMM需要从客户机回收宿主机物理内存时,VMM通知植入客户机操作系统的气球模块,气球发生膨胀,气球模块调用客户机操作系统本身的内存分配函数申请更多的客户机物理内存,VMM相应地把这些客户机物理内存所对应宿主机物理内存回收掉。这些气球模块申请的客户机物理内存名义上还是guest VM的,但实际上已经被VMM控制了,VMM完全可以把这些回收的内存挪作他用。(保留GVA->GPA的映射,取消GPA->HPA的映射)
    • 气球收缩(balloon deflation):当客户机操作系统企图访问被气球回收的客户机物理内存时,由于这些客户机物理内存对应的宿主机物理内存已经被VMM回收,所以会触发page fault缺页错误,并被VMM捕获。VMM按照同样的方法,从其他的guest VM那里回收点内存,放到内存紧缺的这个guest VM的气球里,并让气球收缩以释放内存,之后再重新建立GPA->HPA的映射就可以了。虽然物理页面被VMM替换了,但对于guest VM来说,它的GPA没有变,所以它根本感觉不到。
  • 意义:让有限的物理内存资源在各个guest VM之间得到充分合理的利用。

5、透明页共享技术等
简介: 这个虚机有这么多内存页面,都最终落到物理内存上,有可能不同虚机或同一虚机进程的内存页面,里面的数据是一模一样的,一个驱动运行了两次,一个软件运行了两次等。

原理: 利用指针指向相同的物理内存页面,就节省了空间,这就叫透明页共享技术。

意义:让有限的物理内存资源在各个guest
VM之间得到充分合理的利用,利于内存超分。

总结

  • 提高性能:VMCS中保存有gCR3和nCR3的值,gCR3可以用于访问客户机页表,nCR3可以用于访问ePT/nPT页表,在VM中处于非root模式的CPU可以利用这两个值自动完成GVA->GPA和GPA->HPA这两次地址转换。
  • 减少内存开销:不同于影子页表是一个进程需要一个sPT,EPT/NPT MMU解耦了GVA->GPA转换和GPA->HPA转换之间的依赖关系,一个VM只需要一个ePT/nPT,减少了内存开销。
  • 减少CPU开销:不同于影子页表中,guest VM中发生了page fault,由VMM截获处理。EPT/NPT MMU解耦了GVA->GPA转换和GPA->HPA转换之间的依赖关系,如果guest VM中发生了page fault,可直接由guest OS处理,不会产生VM-Exit,减少了CPU的开销。
  • 提高TLB性能:通过VPID使CPU具备了区分不同的TLB项属于不同VCPU和VMM的能力,避免了在每次VM-Exit和VM-Entry时,使全部TLB失效,提高了VM切换的效率。

参考资料

0

评论区