土法炼钢兴趣小组的算法知识备份

【操作系统百科】x86_64 多级页表

文章导航

分类入口
os
标签入口
#paging#pml4#pcid#la57#cr3

目录

一、先看图

flowchart LR
    VA[48/57 位 VA] --> PML5[PML5E<br/>LA57 开启]
    PML5 --> PML4[PML4E]
    PML4 --> PDPT[PDPTE<br/>1G page 可停]
    PDPT --> PD[PDE<br/>2M page 可停]
    PD --> PT[PTE<br/>4K]
    PT --> PA[物理地址]
    CR3[CR3 寄存器] --> PML4
    classDef reg fill:#a371f722,stroke:#a371f7,color:#adbac7;
    classDef tbl fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    class CR3 reg
    class PML5,PML4,PDPT,PD,PT tbl

二、4 级分页(默认 48 位 VA)

VA 被切成 9+9+9+9+12:

bit  47..39  38..30  29..21  20..12  11..0
     PML4    PDPT    PD      PT      偏移

每级 512 项 × 8 字节 = 4KB 一页(正好一个 page)。走 4 次内存解析一个 VA,MMU 硬件做,称 page walk。

CR3 指向当前进程的 PML4 物理地址;切换地址空间就是换 CR3。

三、5 级分页 LA57

2017 Ice Lake 开始硬件支持 57 位 VA(128PB)。上面多一级 PML5。需要:

查看:grep la57 /proc/cpuinfo

四、大页停止

PDE 的 PSE bit=1 → 这一项不是再下一级表,而是直接 2MB 物理页。PDPTE 同理停 1GB。

所以 x86_64 页大小有 4K / 2M / 1G 三档。huge page 提高 TLB 命中、减少 page walk 成本。

五、PTE 的关键 bit

63      62..52  51..12       11..9 8 7   6 5 4 3 2 1 0
NX      SW/MPK  PA[51..12]   SW    G PAT D A PCD PWT U/S R/W P

六、CR3 切换

一次 fork/exec 后任务切换:

mov %rax, %cr3    # rax = 新 mm->pgd 物理地址

副作用:刷光所有非-global TLB 项。这是进程切换最大开销之一。

七、PCID:TLB 按地址空间标签化

无 PCID 时每次换 CR3 都清 TLB。启用 PCID 后 CR3 低 12 bit 存 12-bit PCID,TLB 按 (PCID, VA) 查,换进程不用清

Linux 4.14+ 默认启用(X86_FEATURE_PCID),每进程分配 PCID(12 bit 所以只 4096 个,循环用)。

INVPCID

专门无效化某个 PCID 的 TLB 条目:

invpcid_flush_single_context(pcid);
invpcid_flush_single_addr(pcid, va);
invpcid_flush_all_nonglobals();

PTI(KPTI)把用户/内核地址空间分开两份页表 → PCID 的价值翻倍。

八、硬件 page walker 与 MMU cache

MMU 不只缓存 TLB,还缓存上层页表项:Paging-structure caches。

所以即使 TLB miss,只要走到”第二级”就能命中上层缓存,省 2-3 次内存。

4 级 walk 若全 miss 要读 4 次 RAM(每次 ~100ns)= ~400ns 纯翻译开销。这是为什么 huge page + Intel ERMS 对某些负载立竿见影。

九、硬件辅助特性

查看:/proc/cpuinfoflags,关注 smep smap pcid invpcid la57 pku

十、页表内存开销

一个进程 ≈ 多少页表内存?

工作集 >100GB 的 DB 不用 huge page 能卡在 TLB 和 page table 开销上。

十一、观察

# 看进程页表大小
grep VmPTE /proc/$$/status

# 看 CPU 特性
grep -oE 'la57|pcid|invpcid|pku|smep|smap|nx' /proc/cpuinfo | sort -u

# x86 raw PTE dump(需 crash/drgn)
drgn -c /proc/kcore -e 'print(find_task(1234).mm.pgd)'

十二、常见坑

A:Transparent PKU / MPK 混用时 fork 后子进程 pkey 可能丢——glibc 2.38+ 有改进 B:LA57 + 老 JIT:某些 JIT 假设 VA 高位 0,越界就崩 C:容器里 PCID/INVPCID 一般能用,但某些老 hypervisor 不透传

十三、小结


参考文献

工具


上一篇虚拟内存模型 下一篇ARMv8 VMSA 页表

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。

2026-05-07 · os

【操作系统百科】用户态分配器

glibc malloc、tcmalloc、jemalloc、mimalloc 各有哲学。本文讲 arena、thread cache、size class、madvise 返还策略、碎片与 RSS 膨胀、如何根据负载选分配器。


By .