C++ / a working model

124 / 163   ·   C11   ·   约 8 分钟

分页:缩小页表

先记住这句话

线性页表会吞噬大量内存。本章用全新表述探讨增大页、分页与分段混合等压缩方法,并指出由此引入的内部碎片与硬件检查代价。

本篇内容
  1. 线性页表的内存膨胀
  2. 更大页的简单权衡
  3. 分页与分段的混合结构
  4. 运行示例
  5. 动手练习

官方章节 PDF

线性页表的内存膨胀

把32位地址空间切成4KiB页会产生大约一百万个虚拟页。每个页表项若占4字节,单进程的线性表就需要4MiB连续内存。系统里同时跑上百个进程时,仅页表就会吃掉数百兆字节,而其中绝大多数表项永远无效。必须寻找压缩办法。

更大页的简单权衡

改用16KiB页立刻把虚拟页数量降到原来的四分之一,线性表缩小到1MiB。代价是内部碎片:程序哪怕只用几KiB也会独占整页,浪费的字节被锁在分配单元内部。因此通用系统仍坚持4KiB或8KiB页。

分页与分段的混合结构

不再用一张覆盖整个地址空间的大数组,而是为代码、堆、栈各建一张紧凑页表。原来的基址寄存器现在存放该段页表的物理地址,界限寄存器记录有效表项个数。虚拟地址高位选出对应表,空洞区域完全不占页表内存。上下文切换时必须同时更新三对基址/界限。

常见误区

  • 只顾缩小页表而盲目采用超大页,可能让内部碎片超过节省的表空间。
  • 混合方案中若忘记在VPN上做段界限检查,进程就能越界访问别人的页表。

运行一个例子

最低标准 C11 · 完整程序 · 下载 .c

#include <stdio.h>
#include <stdint.h>

int main(void) {
    const uint64_t vas_bits = 32;
    const uint64_t page_bits_small = 12;
    const uint64_t pte_bytes = 4;
    uint64_t num_pages_small = 1ULL << (vas_bits - page_bits_small);
    uint64_t pt_size_small = num_pages_small * pte_bytes;
    printf("32-bit address space, 4 KiB pages:\n");
    printf("  Virtual pages: %llu\n", (unsigned long long)num_pages_small);
    printf("  Linear page-table size: %llu bytes (%.1f MiB)\n",
           (unsigned long long)pt_size_small, pt_size_small / (1024.0 * 1024));
    const uint64_t page_bits_large = 14;
    uint64_t num_pages_large = 1ULL << (vas_bits - page_bits_large);
    uint64_t pt_size_large = num_pages_large * pte_bytes;
    printf("\nSame VAS, 16 KiB pages:\n");
    printf("  Virtual pages: %llu\n", (unsigned long long)num_pages_large);
    printf("  Linear page-table size: %llu bytes (%.1f MiB)\n",
           (unsigned long long)pt_size_large, pt_size_large / (1024.0 * 1024));
    printf("\nLarger pages shrink the table by the same factor but waste space inside pages.\n");
    return 0;
}

在本地编译

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-20-advanced-page-tables.c -o example && ./example

预期结果

32-bit address space, 4 KiB pages:
  Virtual pages: 1048576
  Linear page-table size: 4194304 bytes (4.0 MiB)

Same VAS, 16 KiB pages:
  Virtual pages: 262144
  Linear page-table size: 1048576 bytes (1.0 MiB)

Larger pages shrink the table by the same factor but waste space inside pages.

CHECK YOUR UNDERSTANDING

合上答案,试着解释。

32位地址空间、4KiB页、4字节页表项时线性页表多大?改成16KiB页后又多大?新出现什么问题?

查看参考答案

原来4MiB,改后1MiB。内部碎片显著增加,因为未用空间被锁在更大的页内部。

继续查证

标准草案与官方章节会更新;版本标记只说明示例最低要求。

回到目录