# 第 20 章实验:真实进程的页表有多大 ## 做什么 Linux 在 `/proc/self/status` 的 `VmPTE` 一行报告当前进程页表占用的内存。`ptcost.c` 三次写入同样多的数据 (512 页 = 2MB,每页写 1 个字节),只改变它们在虚拟地址空间里的分布,观察页表各增加了多少: 1. 连续 512 页;2. 每页相隔 2MB(跨 1GB);3. 每页相隔 1GB(跨 512GB,用 `MAP_NORESERVE` 只保留地址不占内存)。 ## 怎么跑 ```bash make ./ptcost ``` ## 该观察到什么(WSL2 上的实际结果) ``` 数据 2048 KB 页表 + 12 KB = 3 个页表页 1) 连续 512 页(2MB) 数据 2048 KB 页表 + 2052 KB = 513 个页表页 2) 512 页,每页相隔 2MB(跨 1GB) 数据 2048 KB 页表 + 4100 KB = 1025 个页表页 3) 512 页,每页相隔 1GB(跨 512GB) ``` ## 为什么 x86-64 是 4 级页表:每个页表页 4KB,装 512 个 8 字节项。最底层一页管 2MB 虚拟地址,第三级一页管 1GB。 - 连续 2MB 只需 1 个最底层页表页(加上这块新区域用到的上层页表页)。 - 相隔 2MB:每个数据页各占一个最底层页表页,512 + 1 页。 - 相隔 1GB:连第三级也要各一页,512 + 512 + 1 页。 多级页表只为"用到的区域"分配页表页,所以地址空间越稀疏,每个有效页分摊的页表越多; 但即使最坏的情况,也远小于 48 位线性页表所需的 2^36 × 8 字节 = 512GB。 程序用 `madvise(MADV_NOHUGEPAGE)` 禁止透明大页,否则内核可能用 2MB 大页直接省掉最底层页表。