虚拟内存与分页 · 操作系统
为什么每个程序都以为自己独占了全部内存?
课程目录为什么需要它
两个程序可以都用地址 0x1000 而不冲突,一个程序崩溃不会破坏另一个,能运行的程序比内存装得下的还多。这三件事都来自虚拟内存。它是很多面试题的答案,也能解释「段错误」这类报错,以及换页导致的变慢。
直觉理解
内存被切成固定大小的页(通常 4 KB)。每个进程有一张页表:虚拟页号 → 物理页框号。
翻译一个虚拟地址:
- 页号 = 地址 // 页大小
- 偏移 = 地址 % 页大小
- 在页表里查这个页 → 页框
- 物理地址 = 页框 × 页大小 + 偏移
页表里没有的页(或者标记为「在磁盘上」)会引发缺页:操作系统把它载入;如果地址根本不合法,就杀掉进程(段错误)。
定义
页表
A per-process map from virtual page numbers to physical frames, with flags such as present, writable and user-accessible.每个进程一张的映射表,从虚拟页号映射到物理页框,还带着「在内存中」「可写」「用户可访问」等标志。
缺页 Page fault
An access to a page that isn't currently mapped in RAM. The OS either loads it from disk or, for an invalid address, ends the process.访问了当前没有映射在内存里的页。操作系统要么从磁盘把它载入,要么在地址非法时结束进程。
示例
翻译一个地址
动手试试用 100 字节的页让算术好读一些。真实系统用 4096。
PAGE = 100
page_table = {0: 7, 1: 3, 2: None}
def translate(vaddr):
page, offset = vaddr // PAGE, vaddr % PAGE
frame = page_table.get(page)
if frame is None:
return f"page fault (page {page})"
return frame * PAGE + offset
print(translate(42))
print(translate(150))
print(translate(230))逐步执行
- L542 在第 0 页,偏移 42。
- L9第 0 页在第 7 个页框:742。
742 - L12第 1 页,偏移 50,页框 3。
350 - L13第 2 页不在内存里。
page fault (page 2)
常见错误
以为虚拟地址就是物理地址
程序打印出来的地址是虚拟的。两个进程打印出同一个地址,看的其实是不同的物理内存。
把交换空间当免费内存
内存满了之后,页会被移到磁盘,而磁盘慢几千倍。不停换页(抖动)的机器会慢得像爬。
小测验
1. 这段代码会输出什么?
PAGE = 4096
addr = 9000
print(addr // PAGE, addr % PAGE)查看答案
答案:A
2 × 4096 = 8192,9000 − 8192 = 808。
2. 一个程序读取了一个不属于它任何页的地址。会发生什么?
查看答案
答案:A
这个缺页无法解决,于是操作系统结束这个进程。这种隔离正是目的所在。
动手练习
3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。
- 预测输出手工翻译
准确写出这段程序的输出。
- 改需求遵守只读页
现在页表的每一项是
(页框, 可写)。access(table, vaddr, write)应该返回物理地址;页没有映射时返回"fault";向不可写的页写入时返回"protection"。加上这个保护检查。 - 从零写两个进程,同一个地址
写函数
physical(tables, pid, vaddr, page_size),tables把每个进程 id 映射到它自己的页表({页: 页框})。返回物理地址;该进程没有这个页时返回None。
本课术语
| 术语 | 中文 | 英文定义 |
|---|---|---|
| Virtual memory | 虚拟内存 | Each process sees its own address space, mapped to RAM by the OS. |
| Page | 页 | A fixed-size block of memory, often 4 KB. |
| Page fault | 缺页 | Access to a page not currently in RAM. |
| Segmentation fault | 段错误 | The OS stopping a process that accessed memory it doesn't own. |