课程主页:http://www.cs.cmu.edu/afs/cs/academic/class/15213-f15/www/schedule.html

课程资料:https://github.com/EugeneLiu/translationCSAPP

课程视频:https://www.bilibili.com/video/av31289365/

这一讲介绍了虚拟内存。

地址空间

使用物理地址的系统
  • 用于“简单”系统,例如汽车,电梯和数码相机等设备中的嵌入式微控制器

使用虚拟地址的系统
  • 用于所有现代服务器,笔记本电脑和智能手机
  • 计算机科学的伟大思想之一

地址空间
  • 线性地址空间:连续的非负整数地址的有序集合

  • 虚拟地址空间:$N=2^n$个虚拟地址集合

  • 物理地址空间:$M=2^m$个物理地址集合

为什么使用虚拟内存
  • 有效地使用主存
    • 将DRAM用作部分虚拟地址空间的缓存
  • 简化内存管理
    • 每个进程获得相同的统一线性地址空间
  • 隔离地址空间
    • 一个进程不会干扰另一个进程的内存
    • 用户程序无法访问特权内核信息和代码

虚拟内存作为缓存的工具

  • 从概念上讲,虚拟内存(VM)是磁盘上存储的$N$个连续字节大小的数组。
  • 磁盘上数组的内容缓存在物理内存中(DRAM缓存)
    • 这些高速缓存块称为页面(大小为$P=2^p$字节),称为物理页面(PP)
  • 虚拟内存有对应的虚拟页面(VP)
    • 在任意时刻,虚拟页面分为三个不相交的集合:
      • 未分配的:VM系统还未分配(或创建)的页。
      • 缓存的:当且已缓存在物理内存中的已分配页。
      • 未缓存的:未缓存在物理内存中的已分配页。

DRAM缓存的组织结构
  • DRAM高速缓存组织结构受到巨大的未命中惩罚的驱动
    • DRAM大约比SRAM慢10倍
    • 磁盘比DRAM慢10,000倍
  • 结果
    • 较大的页面(块),大小:通常为4KB,有时为4MB
    • 全相联
      • 任何VP可以放置在任何PP中
      • 需要“大”映射函数——与高速缓存不同
    • 高度复杂,昂贵的替换算法
      • 过于复杂且开放式,无法在硬件中实现
    • 写回而不是直写
启用数据结构:页表
  • 页表是将虚拟页映射到物理页的页表项(PTE)数组
    • DRAM中的按进程内核数据结构

页命中
  • 页命中:引用物理内存中的VM字(DRAM缓存命中)
    • 例如定位PTE2

缺页
  • 页面错误:引用不在物理内存中的VM字(DRAM缓存未命中)

处理缺页
  • 页面遗漏导致缺页(异常)
  • 页面错误处理程序选择牺牲页(此处为VP 4)
  • 复制VP 3到内存中的PP 3,更新PTE 3,随后返回,重启导致缺页的指令,该指令会把导致缺页的虚拟地址重新发送到地址翻译硬件,此时VP 3已缓存在主存中

分配页面

分配虚拟内存的新页面(VP 5)

局部性救了我们
  • 虚拟内存似乎效率极低,但是由于局部性,它工作的相当好。
  • 在任何时间点,程序都倾向于访问称为工作集的一组活动虚拟页面。
    • 时间局部性更好的程序将具有较小的工作集
  • 如果(工作集大小<主存大小)
    • 进程性能良好
  • 如果(SUM(工作集大小)>主存大小)
    • 抖动:性能崩溃,其中页面不断进行交换(复制)

虚拟内存作为内存管理的工具

  • 关键思想:每个进程都有自己的虚拟地址空间
    • 它可以将内存视为简单的线性数组
    • 映射函数通过物理内存分散地址
      • 精心选择的映射可以改善局部性
  • 简化内存分配
    • 每个虚拟页面都可以映射到任何物理页面
    • 虚拟页面可以在不同时间存储在不同的物理页面
  • 在进程之间共享代码和数据
    • 将虚拟页面映射到同一物理页面(此处:PP 6)

简化链接和加载
  • 链接
    • 每个程序都有相似的虚拟地址空间
    • 代码,数据和堆总是从相同的地址开始
  • 加载
    • execve为.text和.data节分配虚拟页并创建标记为无效的PTE
    • 虚拟内存系统按需逐页复制.text和.data节

虚拟内存作为内存保护的工具

  • 用权限位扩展PTE
  • MMU(内存管理单元)在每次访问时检查这些位

地址翻译

  • 虚拟地址空间(VAS)

    • $V=\{0,1, \ldots, N-1\}$
  • 物理地址空间(PAS)

    • $P=\{0,1, \ldots, M-1\}$
  • 地址翻译

    • 映射:$V \rightarrow P \cup \{\varnothing\}$

地址翻译符号总结
使用页表进行地址转换

地址翻译:页面命中
  1. 处理器生成一个虚拟地址,并把它传送给MMU。
  2. MMU生成PTE地址,并从高速缓存/主存请求得到它。
  3. 高速缓存/主存向MMU返回PTE。
  4. MMU构造物理地址,并把它传送给高速缓存/主存。
  5. 高速缓存/主存返回所请求的数据字给处理器。

地址翻译:缺页

  1. 处理器生成一个虚拟地址,并把它传送给 MMU。
  2. MMU生成PTE地址,并从高速缓存/主存请求得到它。
  3. 高速缓存/主存向MMU返回PTE。
  4. PTE中的有效位是零,所以MMU触发了一次异常,传递CPU中的控制到操作系统内核中的缺页异常处理程序。
  5. 缺页处理程序确定出物理内存中的牺牲页,如果这个页面已经被修改了,则把它换出到磁盘。
  6. 缺页处理程序页面调入新的页面,并更新内存中的PTE。
  7. 缺页处理程序返回到原来的进程,再次执行导致缺页的指令。
结合高速缓存和虚拟内存

利用TLB加速地址翻译
  • 页表条目(PTE)像其他任何存储字一样被缓存在L1中

    • PTE可能会被其他数据引用驱逐
    • PTE命中仍然需要较小的L1延迟
  • 解决方案:翻译后备缓冲区(TLB)

    • MMU中的小型集关联硬件缓存
    • 将虚拟页码映射到物理页码
    • 包含少量页面的完整页面表条目
  • MMU使用虚拟地址的VPN部分访问TLB

TLB命中

TLB不命中

多级页表
  • 假设:
    • 4KB($2^{12}$)页面大小,48位地址空间,8字节PTE
  • 问题:
    • 需要一个512 GB的页表!
      • $2^{48} \times 2^{-12} \times 2^3 = 2^{39}$字节
  • 常见解决方案:多级页表
  • 示例:2级页表
    • 1级表:每个PTE指向一个页表
    • 2级表:每个PTE都指向一个页面

使用$k$级页表进行地址翻译

总结

  • 程序员对虚拟内存的看法
    • 每个进程都有自己的私有线性地址空间
    • 不会被其他进程破坏
  • 虚拟内存的系统视图
    • 通过缓存虚拟内存页面有效地使用内存
      • 因为局部性而有效
    • 简化内存管理和编程