作者:mosun,腾讯 PCG 后台开发工程师
一、虚拟内存1.1 引入虚拟内存我们知道计算机的起源 CPU、由三个核心部分组成:存储器、输入/输出设备,如下:
CPU 在完全理想的状态下,存储器应具备以下三个特性:
足够快:这样 CPU 效率不受存储器的限制;足够大的容量:容量可以存储计算机所需的所有数据;足够便宜:便宜,所有类型的计算机都可以配备;然而,出于成本考虑,在目前的计算机系统中,存储采用分层设计,常见层次如下:
上图是寄存器、高速缓存、主存和磁盘,它们的速度、成本和容量在计算机中逐渐增加。物理内存通常被称为上述主存,通常被用作操作系统或其他程序的临时数据存储介质。通常,我们称之为物理内存,即上述主存,通常用作操作系统或其他程序的临时数据存储介质。在嵌入式和一些旧的操作系统中,系统通过物理搜索直接处理主存储器。然而,随着科学技术的发展,遇到了以下困境:
一台机器可以同时运行多个大型应用程序;每个应用程序都需要存储大量的临时数据;早期,单个 CPU 寻址能力 2^32.内存最大 4G;主存成为计算机系统的瓶颈。科学家们提出了一个概念:虚拟内存。
以 32 以位操作系统为例,虚拟内存的引入使操作系统能够将每个过程分配到大小 4GB 虚拟内存空间实际上只有在物理内存需要时才会加载,有效解决了物理内存有限空间带来的瓶颈。从虚拟内存到物理内存转换的过程中,地址翻译是非常重要的一步。
1.2 地址翻译运行过程中产生的内存地址为虚拟地址。如果计算机没有引入存储器抽象技术的虚拟内存,则 CPU 将这些地址直接发送到内存地址总线,然后访问与虚拟地址相同值的物理地址;如果使用虚拟内存技术,CPU 通过地址总线将这些虚拟地址发送到内存管理单位(Memory Management Unit,简称 MMU),MMU 将虚拟地址翻译成物理地址,然后通过内存总线访问物理内存:
虚拟地址(例如 16 位地址 8196=0010 0000000部分:虚拟页号(Virtual Page Number,简称 VPN,这里是高 4 位部)和偏移量(Virtual Page Offset,简称 VPO,这里是低 12 位拟地址通过页面转换为物理地址(page table)来实现的。页面由多个页面项组成(Page Table Entry, 简称 PTE)一般来说,物理页框号、修改位、访问位、保护位和 ";在/不在" 位(有效位)等信息。
在这里,我们基于一个例子来分析计算机硬件在页面命中时是如何交互的:
第 1 步:处理器生成虚拟地址 VA,通过总线发送 MMU;第 2 步:MMU 页面项的地址通过虚拟页号获得 PTEA,从内存总线 CPU 高速缓存/主存读取页面项 PTE;第 3 步:CPU 通过内存总线高速缓存或主存 MMU 返回页表项 PTE;第 4 步:MMU 首先,页面项中的物理页框号 PPN 复制到寄存器的高三位,接着把 12 位的偏移量 VPO 复制到寄存器的末端 12 位构成 15 位置的物理地址,即寄存器存储的物理内存地址 PA 将其发送到内存总线,访问高速缓存/主存;第 5 步:CPU 高速缓存/主存返回物理地址对应的数据给处理器。在 MMU 转换地址时,如果页面项的有效性是 0,这意味着页面没有映射到真实的物理页框号 PPN,会导致一个缺页中断,CPU 陷入操作系统的核心,然后操作系统会通过页面置换算法选择页面来替换 (swap),为即将调入的新页腾出位置,如果设置了要更改的页面页面项中的修改位置,即更新,则为脏页 (Dirty Page),如果页面是磁盘上的副本,则需要写回磁盘更新页面。"干净";是的,也就是说,如果没有修改,可以直接用转入的新页面覆盖被替换的旧页面。缺页中断的具体流程如下:
第 1 步到第 3 步:前页命中前页 3 步骤一致;第 4 步:检查返回的页表项 PTE 发现其有效位是 0,则 MMU 触发缺页中断异常,然后 CPU 缺页中断处理器转入操作系统内核;第 5 步:检查缺页中断处理程序所需的虚拟地址是否合法,系统检查是否有空闲物理页框号 PPN 它可以映射到缺失的虚拟页面。如果没有空闲页面框,则执行页面替换算法,以找到现有的虚拟页面被淘汰。如果页面已经修改,请将其写回磁盘,更新磁盘上页面的副本;第 6 步:缺页中断处理程序从磁盘转移到,更新页面项 PTE;第 7 步:缺页中断程序返回原始过程,重新执行导致缺页中断的指令,CPU 重新发送导致缺页中断的虚拟地址 MMU,此时虚拟地址已经有了映射物理页框号 PPN,所以会遵循前面『Page Hit』再走一遍流程,最后,主存将要求的数据返回到处理器。1.2.1 高速缓存在分析虚拟内存的工作原理时,当谈到页面的存储位置时,为了简化处理,默认将主存储和高速缓存放在一起,事实上,更详细的过程应该是以下原理图:
如果计算机配备了虚拟内存技术和 CPU 高速缓存,那么 MMU 每次都会优先考虑高速缓存寻址,如果缓存命中会直接返回,只有缓存不命中后才会去主存寻址。
一般来说,大多数系统会选择使用物理内存地址访问高速缓存,因为高速缓存比主存储器要小得多,所以使用物理地址不会太复杂;此外,由于高速缓存容量很小,系统需要在多个过程之间共享数据块,物理地址的使用可以使多个过程同时存储数据块和共享来自同一虚拟内存页面的数据块更加直观。
1.2.2 加速翻译&优化页表虚拟内存技术能否真正广泛应用于计算机,还需要解决以下两个问题:
从虚拟地址到物理地址的映射过程必须非常快,如何加快地址翻译。1.2.2 加速翻译&优化页表
虚拟内存技术能否真正广泛应用于计算机,还需要解决以下两个问题:从虚拟地址到物理地址的映射过程必须非常快,如何加快地址翻译。虚拟地址范围的扩大将不可避免地导致页面扩展,形成大页面。"计算机科学领域的任何问题都可以通过增加间接的中间层来解决"。虽然虚拟内存本身就是一个中间层,但中间层中的问题也可以通过引入另一个中间层来解决。目前,通过引入页面缓存模块来加速地址翻译过程的方案 -- TLB,大页实现多级页表或倒排页表来解决大页表。
1.2.2.1 TLB 加速翻译后备缓冲器
(Translation Lookaside Buffer,TLB),又称快表,由于虚拟内存的分页机制,由于虚拟内存的分页机制,页表一般是保存在内存中的固定存储区,而 MMU 每次翻译虚拟地址时,都需要从页面上匹配相应的地址 PTE,导致过程通过 MMU 访问指定的内存数据时,内存访问比没有分页机制的系统多一次,通常需要几十到几百个 CPU 如果时钟周期性能下降至少一半, PTE 碰巧缓存在 CPU L1 在高速缓存中,费用可以降低到一两个周期,但我们不能每次都希望匹配 PTE 都刚好在 L1 因此,需要引入加速机制,即 TLB 快表。TLB 它可以简单地理解页表的高速缓存,并保存最高频率的页表项 PTE。由于 TLB 一般是硬件实现的,所以速度很快,MMU 当你收到虚拟地址时,你通常会先通过硬件 TLB 并行匹配页行匹配相应的页面 PTE,若命中且该 PTE 访问操作不违反保护位(如试图写一个只读的内存地址),直接从 TLB 取出相应的物理页框号 PPN 返回,如果不命中,会穿透主存页表查询,查询最新页面项后存储 TLB,为下次缓存命中做好准备 TLB 目前存储空间不足将取代现有存储空间之一 PTE。
下面具体分析一下 TLB 命中和不命中。TLB 命中:第 1 步:CPU 产生虚拟地址 VA;第 2 步和第 3 步:MMU 从 TLB 取出相应的 PTE;第 4 步:MMU 虚拟地址 VA 翻译成真实的物理地址 PA,高速缓存/主存通过地址总线发送;
第 5 步:高速缓存/主存将物理地址 PA 返回上述数据 CPU。TLB 不命中:第 1 步:CPU 产生虚拟地址 VA;第 2 步至第 4 步:查询 TLB 失败,通过正常的主存页表查询流程获取 PTE,然后把它放进去 TLB 如果缓存,以备下次查询, TLB 此时存储空间不足,此操作将被替换 TLB 另一个存在 PTE;第 5 步:MMU 虚拟地址 VA 翻译成真实的物理地址 PA,高速缓存/主存通过地址总线发送;
第 6 步:高速缓存/主存将物理地址 PA 返回上述数据 CPU。1.2.2.2 多级页表
TLB 从虚拟地址到物理地址解决从虚拟地址到物理地址翻译的成本问题,然后还需要解决另一个问题:大页表。1.2.2.2 多级页表
TLB 引入可以在一定程度上解决从虚拟地址到物理地址翻译的成本问题,然后还需要解决另一个问题:大页表。 32 计算机的找址空间是 4GB,也就是说,理论上每个运行在计算机上的过程的虚拟搜索范围是 4GB。到目前为止,我们一直在讨论单页表的情况。如果每个过程都将理论上可用的内存页面装载到一个页面表中,但事实上,过程中真正使用的内存可能只是一小部分,我们也知道页面表也保存在计算机主存中,必然会造成大量内存浪费,甚至可能导致计算机物理内存不足,无法平行运行更多过程。这个问题通常是通过的多级页表(Multi-Level Page Tables)为了解决这个问题,通过拆分一个大页表,形成一个多层次的页表,让我们看看如何设计一个二级页表:假设虚拟地址是 32 位,由 10 一级页面索引,10 二级页面索引和位置 12 位置地址偏移,则 PTE 是 4 字节,页面 page 大小是 2^12 = 4KB,总共需要 2^20 个 PTE,一级页面中的每一个 PTE 负责映射虚拟地址空间中的一个 4MB 的 chunk,每一个 chunk 都由 1024 连续页面 Page 如果找址空间是组成, 4GB,所以一共只需要 1024 个 PTE 足以覆盖整个过程地址空间。二级页面中的每一个 PTE 都负责映射一个 4KB 虚拟内存页面的原理与单页表相同。二级页面中的每一个 PTE 都负责映射一个 4KB 虚拟内存页面的原理与单页表相同。多级页表的关键在于,我们不需要一级页表中的每一个 PTE 分配一个二级页表,只需分配和映射当前使用的地址。因此,对于大多数过程来说,它们的一级页表中有大量空置 PTE,那么这部分 PTE 没有必要存在相应的二级页表,这是一个相当可观的内存节,事实上,对于一个典型的程序,理论上 4GB 大多数可用的虚拟内存地址空间将处于如此未分配的状态;此外,在程序运行过程中,只需在主存储中放置一级页表,虚拟内存系统可以在实际需要时创建、转移和转移二级页表,以确保只有最常用的二级页表才能永久存储在主存储中,这也大大缓解了主存储器的压力。
二、 内核空间 & 用户空间对 32 就位置操作系统而言,其搜索空间(虚拟地址空间或线性地址空间)为 4G(2 的 32 次方