Lazy loaded image
🖥️虚拟内存
Words 3448Read Time 9 min
2025-1-20
2025-4-6
type
status
date
slug
summary
tags
category
icon
password
类型
标签
状态
notion image
每个程序拥有自己的地址空间,这个空间被分割成多个块,每一块称作一页或页面(page)。每一页有连续的地址范围。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分物理内存中的地址空间时,由硬件立刻执行必要的映射。当程序应用到一部分不在内存中的地址空间时,由操作系统负责讲缺失的部分装入物理内存并执行失败指令。
虚拟内存是对基址寄存器和界限寄存器的一种综合。他使得整个地址空间可以用相对较小的单元映射到物理内存,而不是为正文段和数据短分别进行重定位。
以下为实现虚拟内存的方法:
  1. 分页
    1. 在任何一台计算机上,程序引用了一组内存地址。当程序执行指令:
      时,它把地址为1000的内存单元的内容复制到REG中。地址可以通过索引、基址寄存器、段寄存器或其他方式产生。
      由程序产生的这些地址称为虚拟地址(virtual address),它们构成了一个虚拟地址空间(virtual address space)。
      • 在没有虚拟内存的计算机上,系统直接将虚拟地址送到内存总线上,读写操作使用同样地址的物理内存字;
      • 而在使用虚拟内存的情况下,虚拟地址不是直接送到内存总线上,而是被直接送到内存管理单元(Memory Management Unit,MMU),MMU把虚拟地址映射为物理内存地址。
      notion image
      上述映射的工作原理:
      现在假设有一个可以产生16位地址的计算机,地址范围从0到64K,且这些地址是虚拟地址。然而这台计算机只有32K的物理内存,因此,虽然可以编写64KB程序,但它却不能完全调入内存运行。在从磁盘上必须有一个大到64KB的程序核心映像的完整副本,以保证程序片段在需要时能被调入内存。
      notion image
      虚拟地址空间按固定大小划分成我们称为页面(page)的若干单元。在物理内存中对应的单元1称为页框(page frame)。页面和页框的大小通常是一样的(这里是4KB)。
      当程序试图访问地址0时,执行下面这条指令:
      将虚拟地址0送到MMU。MMU看到虚拟地址落在页面0.根据其映射结果,这一页面对应的是页框2(8192 ~12 287),因此MMU把地址变换为8192,并把地址8192送到总线上。内存对MMU一无所知,它只看到一个读或写地址8192的请求并执行它。MMU从而有效地把所有从0~4095的虚拟地址映射到了8192~12 287的物理地址。
      通过恰当设置MMU,可以把16个虚拟页面映射到8个页框中的任何一个。并且在实际硬件中通过使用一个”在/不在“位(present/absent bit)记录页面在内存中的实际存在情况。
      当程序访问了一个未映射的页面,MMU会注意到页面没有被映射,于是使CPU陷入到操作系统,,这个陷阱称为缺页中断(page fault)。这种情况下,操作新系统找到一个很少使用的页框且把它的内容写入磁盘。然后把需要访问的页面读到刚才回收的页框中,修改映射关系,然后重新启动引起陷阱的指令。
      MMU的内部结构如下(16个4KB页面):
      notion image
      输入的16位虚拟地址被分为4位的页号和12位的偏移量。4位的页号可以表示16个页面,12位的偏移可以为一页内的全部4096个字节编址。
      可以用页号作为页表(page table)的索引,以得出对应于该虚拟页面的页框号。如果”在/不在“位是0,则将引起一个操作系统陷阱。如果该位是1,则将在页表中查到的页框号复制大奥输出寄存器的高3位中,再加上输入虚拟地址中的低12位偏移量。久=就构成了15位的物理地址。输出寄存器的内容随即被作为物理地址送到地址总线。
  1. 页表
    1. 页表是一种虚拟内存最简单的实现,将虚拟地址分为虚拟页号(高位部分)和偏移量(低位部分)两部分。例如,对于16位地址和4KB的页面大小,高4位可以指定16个虚拟页面中的一页,而低12位接着确定了所选页面中的字节偏移量(0~4095)。
      虚拟页号可用做页表的索引,以找到该虚拟页面对应的页表项。由页表项可以找到页框号(若有)。然后把页框号拼接到偏移量的高位端,以替换掉虚拟页号,形成送往内存的物理地址。
      页表的目的是把虚拟页面映射到页框。页表可用看作一个函数,它的参数是虚拟页号,结果是物理页框号,通过这个函数可以把虚拟地址中的虚拟页面域替换成页框域,从而形成物理地址。
    2. 页表项的构成
      1. 最重要的域是页框号(映射的目的就是照这个值),其次是”在/不在“位,这一位是1时表示该表项是有效的;”保护“位指出一个页面允许什么类型的访问;引入”修改“位和”访问“位来记录页面的使用情况。还有一位用来”禁止该位被高速缓存“。
        notion image
        若某个页面不在内存时,用于保存该页面的磁盘地址不是页表的一部分。因为页表只保存把虚拟地址转换为物理地址时硬件所需要的信息。操作系统在处理缺页中断时需要把该页面的磁盘地址等信息保存在操作系统内部的软件表格中,硬件不需要它。
  1. 加速分页过程
    1. 任何的分页系统中总会考虑两个问题
      • 虚拟内存到物理地址的映射必须非常快
      • 如果虚拟地址空间很大,页表也会很大
      对大而快速的页映射的需求成为了构建计算机的重要约束。最简单的设计是使用由一组“快速硬件寄存器”组成的单一页表,每一个表项对应一个虚页,虚页号作为索引。但当页表很大时,这样做代价很高。且每次上下文切换必须装载整个页表,一定会降低性能。
      另有一种方法:整个页表都在内存中。那时所需的硬件仅仅是一个指向页表起始位置的寄存器。这样的设计使得在上下文切换时,进行“虚拟地址到物理地址”的映射只需重新装入一个寄存器。这种做法的缺陷是:在执行每条指令时,都需要一次或多次内存访问,以完成页表项的读入,速度非常慢。
    2. 转换检测缓冲区(Translation Lookaside Buffer,TLB)
      1. 也称相联存储器(associatememory),它通常在MMU中,包含少量的表项,每个表项记录了一个页面相关信息,包括虚拟页号、页面的修改位、保护码(读写/执行权限)和该页所对应的物理页框。
        除了虚拟页号(不是必须放在页表中的),这些域与页表中的域是一一对应的。另 外还有一位用来记录这个表项是否有效(即是否在使用)。
        TLB工作时,将一个虚拟地址放入MMU中进行转换时,硬件首先通过将该虚拟页号与TLB中所有表项同时(即并行)进行匹配,判断虚拟页面是否在其中。如果发现了一个有效的匹配并且要进行的访问操作并不违反保护位,则将页框号直接从TLB中取出而不必再访问页表。如果虚拟页面号确实是在TLB中,但指令试图在一个只读页面上进行写操作,则会产生一个保护错误,就像对页表进行非法访问一样。
        如果MMU检测到没有有效的匹配项时,就会进行正常的页表查询。接着从TLB中淘汰一个表项,然后用新找到的页表项代替它
    3. 软件TLB管理
      1. 对TLB的管理和TLB的失效处理都完全由MMU硬件来实现。只有在内存中没有找到某个页面时,才会陷入到操作系统中。
        当TLB大到可以减少失效率时,TLB的软件管理就会变得足够有效。该方法获得了一个非常简单的MMU,这就在CPU芯片上为高速缓存以及其他设计腾出了很大的空间。
        无论是用硬件还是用软件来处理TLB失效,常见方法都是找到页表并执行索引操作以定位将要访问的页面。
        用软件做这样的搜索的问题是,页表可能不在TLB中,这就会导致处理过程中的额外的TLB失效。当使用软件TLB管理时,一个基本要求是要理解两种不同的TLB失效的区别在哪里:
        • 当一个页面访问在内存中而不在TLB中时,将产生软失效(softmiss)。那么此时所要做的就是更新一下TLB,不需要产生磁盘I/O。
        • 当页面本身不在内存中(当然也不在TLB中)时,将产生硬失效。此刻需要一次磁盘存取以装入该页面,这个过程大概需要几毫秒。硬失效的处理时间往往是软失效的百万倍。
  1. 针对大内存的页表
    1. 在原有的内存页表的方案之上,引入快表(TLB)可以用来加快虚拟地址到物理地址的转换。
      对于如何处理巨大的虚拟内存空间,以下给出两种方法:
    2. 多级页表
      1. 如下图所示,32位的虚拟地址被划分为10位的PT1域,10位的PT2域和12位的Offset(偏移量)域。
        notion image
        由索引顶级页表得到的表项中含有二级页表的地址或页框号。顶级页表的表项0指向程序正文的页表,表项1指向数据的页表,表项1023指向堆栈的页表,其他的表项(用阴影表示的)未用。现在把PT2域作为访问选定的二级页表的索引,以便找到该虚拟页面的对应页框号。
        若访问时强制产生了一个缺页中断,操作系统将注意到进程正在试图访问一个不希望被访问的地址,并采取适当的行动,如向进程发出一个信号或杀死进程等。
    3. 倒排页表(inverted page table)
      1. 对于64位虚拟地址空间,在实际内存中每一个页框都有一个表项,而不是在每一个虚拟页面有一个表项。对于64位虚拟地址,4KB的页,1GB的RAM,一个倒排页表仅需要262 144个页表项。表项记录哪一个(进程,虚拟页面)对定位于该页框。
        虽然倒排页表节省了大量空间,但是从虚拟地址到物理地址的转换会变得很 困难。而使用TLB可以解决,如果TLB能够记录所有频繁使用的页面,地址转换就可能变得像通常的页表一样快。
        但是,当发生TLB失效时,需要用软件搜索整个倒排页表。一个可行的实现该搜索的方法是建立一张散列表,用虚拟地址来散列。当前所有在内存中的具有相同散列值的虚拟页面被链接在一起。如下图所示:
        notion image
上一篇
文件和目录
下一篇
IPC(进程间通信)问题