VM 原语的力量
Trap、Prot1/ProtN、Unprot、Dirty、Map2 让应用利用缺页驱动计算。
6.1810 / 6.1810 · 第 10 课 · rtm
操作系统内核使用虚拟内存实现按需分页、共享内存等机制。Appel & Li (1991) 的核心论点:用户级应用同样能从虚拟内存原语中获益——并发 GC、检查点、分布式共享内存等都可通过缺页异常驱动。
论文提出的应用级 VM 原语:
| 原语 | 作用 |
|---|---|
Trap | 在用户态处理缺页异常 |
Prot1 | 降低一个页面的可访问性 |
ProtN | 降低 N 个页面的可访问性 |
Unprot | 提升一个页面的可访问性 |
Dirty | 返回自上次调用以来被修改的页面列表 |
Map2 | 将同一物理页映射到两个不同 VA,使用不同保护级别 |
xv6 不支持任何这些原本。好的操作系统应该支持它们。今天的 Unix 呢?
mmap() —— 映射内存到地址空间// 映射文件
mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, offset);
// 匿名内存(优于 sbrk)
mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
mprotect() —— 改变映射的保护级别mprotect(addr, len, PROT_READ); // 只读
mprotect(addr, len, PROT_NONE); // 不可访问,访问将触发异常
munmap() —— 移除映射munmap(addr, len);
sigaction() —— 注册信号处理器act.sa_sigaction = handle_sigsegv;
act.sa_flags = SA_SIGINFO;
sigemptyset(&act.sa_mask);
sigaction(SIGSEGV, &act, NULL);
madvise(), mincore(), mremap(), msync(), mlock(), mbind(), shmat() 等。
| 原语 | Unix 实现 | 是否完全支持 |
|---|---|---|
| Trap | sigaction + SIGSEGV | 是 |
| Prot1 | mprotect() | 是 |
| ProtN | mprotect() | 是 |
| Unprot | mprotect() | 是 |
| Dirty | 无直接支持,但有 workaround | 部分 |
| Map2 | 不直接,但 shm_open+mmap 可模拟 | 部分 |
地址空间由 VMA 和页表组成。每个 VMA 是一段连续的虚拟地址范围,具有相同的权限,由同一对象(文件或匿名内存)支持。VMA 帮助内核决定如何处理缺页。
应用代码认为有一个预计算的大表 sqrts[n]。表大于物理内存,但用户级 VM 原语只让它占用一个物理页。每次访问新项时触发缺页,处理器计算并解保护该页。
实测(2024):一次缺页约 10233μs / 1000 = ~10μs;一次加法约 0.417ns,即 ~24000 次加法等价于一次缺页。
free传统实现需要语言/编译器支持(插桩 load/store),而用户级 VM 可以避免插桩,更快。
baker.c)堆分为 from-space 和 to-space。to-space 进一步分为 scanned、unscanned 和 new:
alloc 便宜:压缩式,无需空闲列表复制根之后,取消映射 to-space 的 unscanned 部分。当线程访问 unscanned 区域时触发缺页:
回收器线程可与应用线程并发运行:回收器扫描完一页后 UNPROT 即可。唯一需要的同步是"哪个线程在扫描哪一页"。
现状:很少有系统使用 Baker 算法(它复制所有存活对象),但 VM 思想很酷。
将进程从机器 M1 迁移到 M2(如升级 M1)。朴素方案:检查点 P → 复制到 M2 → 重启 P。问题是复制内存可能很慢。
可以重叠发送内存与运行 P 的时间。需要 Trap 和 ProtN 原语。
P 继续在 M1 运行,同时复制检查点(含内存)到 M2。跟踪 P 修改的页面,取消映射内存,缺页时记录该页需发送。
mlock, madvise, mremap, mincore 等更多控制Q1:Appel & Li 论文提出的 6 个用户级 VM 原语中,哪一项 Unix 无法直接支持?
Q2:Baker 实时 GC 算法使用 VM 的主要目的是什么?
Q3:在 Baker 算法的 VM 实现中,当应用线程访问 unscanned 区域时会发生什么?
Q4:使用用户级 VM 进行虚拟机迁移的主要好处是什么?
Q5:为什么论文时代的缺页陷阱(~1200μs)并非 GC 的障碍?
Trap、Prot1/ProtN、Unprot、Dirty、Map2 让应用利用缺页驱动计算。
避免插桩 load/store,用缺页驱动扫描,易于并发化。
取消映射内存,缺页时按需获取,可重叠传输与执行。
1991 至今,VM API 持续扩展,应用对 VM 的控制力不断增强。
sqrts.c —— 单页平方根表演示代码baker.c —— Toy Baker GC 实现