Paging 和 segmentation 是组织一个虚拟地址空间的两种方式;现代系统压倒性地基于 paging(有时在其上叠加薄薄一层 segmentation)。
Paging
虚拟内存和物理内存被切成固定大小的(通常 4 KB)。一个 把虚拟页映射到物理 frame。一个地址被拆分成一个(进入表的索引)和一个 :
virtual address = [ page number | offset ]
│ │
page table[page] = frame │
▼ ▼
physical address = [ frame | offset ]
Page table 很大,所以它们是多级的(multi-level)(一棵树)或经过哈希,并由硬件 MMU 遍历(walk)。
在每一次内存访问时都遍历一个多级 page table 会让系统瘫痪。TLB(Translation Lookaside Buffer) 是 CPU 内部一个小而快的 cache,缓存最近的虚拟→物理翻译:
CPU needs addr → TLB hit? ── yes ──▶ get frame immediately (~1 cycle)
│
└── no (TLB miss) → walk the page table, fill the TLB (slower)
TLB 命中率通常 >99%;一次 miss 代价高昂,这就是为什么**空间局部性(spatial locality)**以及诸如 huge page(2 MB——覆盖相同 RAM 所需的 entry 更少)之类的特性对性能很重要。
如果 page-table entry 表明该页不在 RAM 中(或其保护位被违反),MMU 就抛出一个 page fault trap。操作系统处理它:从磁盘装入该页(一次 major fault)、用零填充一个新页,或做 copy-on-write。一次命中磁盘的 page fault 要花数百万个 cycle——因此把 working set 保留在 RAM 中才重要。
Segmentation 按逻辑单元——code、data、stack——把内存分成可变大小的 segment,以 [segment selector | offset] 寻址。它自然地映射到程序结构,但会遭受外部碎片(external fragmentation)(可变大小的空洞)。纯 segmentation 大体上已成历史;x86 保留了一种残余形式,但 Linux 把它压平,转而依赖 paging。
Paging、TLB 和 page fault 是“虚拟内存”与真实性能相遇之处。面试官用它来检查你是否能把抽象与硬件成本联系起来:为什么 huge page 减少 TLB miss、为什么一场 page-fault 风暴会拖垮延迟、以及为什么对 cache/TLB 友好的访问模式跑得快。它也是 memory-mapped file、copy-on-write 和 thrashing 的必备背景。
一个包含详细解答的 IT 面试题库——从初级到高级。
捐赠