3. 分页机制详解:页表结构(四级页表)、TLB原理、大页(HugePage)与透明大页
分页(Paging)是现代操作系统内存管理的核心机制,它将虚拟地址空间划分为固定大小的页(Page),并将物理内存划分为同样大小的页框(Page Frame)。本章深入剖析Linux内核中四级页表的结构、TLB(Translation Lookaside Buffer)的工作原理,以及大页(HugePage)与透明大页(Transparent HugePage)的实现与应用。
3.1 四级页表结构
在x86-64架构下,Linux内核采用四级页表结构来管理虚拟地址到物理地址的转换。这种层级结构有效解决了大地址空间(48位虚拟地址)下的页表存储与查找效率问题。
3.1.1 四级页表层级
四级页表由以下四个层级组成,每一级负责索引虚拟地址中的不同部分:
| 层级 | 英文缩写 | 全称 | 索引位数 | 页表项大小 |
|---|---|---|---|---|
| 页全局目录 | PGD | Page Global Directory | 9 bits | 8 bytes |
| 页上级目录 | P4D | Page 4th-level Directory | 9 bits | 8 bytes |
| 页中间目录 | PUD | Page Upper Directory | 9 bits | 8 bytes |
| 页表 | PTE | Page Table Entry | 9 bits | 8 bytes |
虚拟地址的组成结构如下:
63 48 47 39 38 30 29 21 20 12 11 0
+-------------+------------+------------+------------+------------+------------+
| 符号扩展 | PGD索引 | P4D索引 | PUD索引 | PMT索引 | 页内偏移 |
| (16 bits) | (9 bits) | (9 bits) | (9 bits) | (9 bits) | (12 bits) |
+-------------+------------+------------+------------+------------+------------+
3.1.2 四级页表地址转换流程
地址转换过程从MMU(Memory Management Unit)开始,依次遍历四级页表:
- PGD查找:从虚拟地址中提取PGD索引,在进程的PGD基址寄存器指向的页表中找到对应的PGD表项。
- P4D查找:PGD表项指向P4D页表的基址,使用P4D索引找到对应的P4D表项。
- PUD查找:P4D表项指向PUD页表的基址,使用PUD索引找到对应的PUD表项。
- PMT查找:PUD表项指向PMT页表的基址,使用PMT索引找到对应的PTE(页表项)。
- 物理地址计算:PTE中包含物理页框号(PFN),将PFN与页内偏移组合得到最终的物理地址。
3.1.3 四级页表结构SVG图
3.2 TLB原理
TLB(Translation Lookaside Buffer)是CPU内部的一个高速缓存,专门用于缓存最近使用的虚拟地址到物理地址的转换结果。由于四级页表转换需要多次内存访问,TLB的存在极大提升了地址转换效率。
3.2.1 TLB结构
TLB通常分为指令TLB(ITLB)和数据TLB(DTLB),并采用全相联或组相联的缓存结构。每个TLB条目包含以下字段:
| 字段 | 说明 | 作用 |
|---|---|---|
| 虚拟页号(VPN) | 虚拟地址的页号部分 | 用于匹配TLB条目 |
| 物理页框号(PFN) | 对应的物理页框号 | 直接用于地址转换 |
| 权限位 | 读/写/执行权限 | 控制访问权限 |
| ASID | 地址空间标识符 | 区分不同进程的地址空间 |
| 有效位 | 条目是否有效 | 标记缓存是否可用 |
3.2.2 TLB命中与缺失
TLB的工作流程分为命中(Hit)和缺失(Miss)两种情况:
- TLB命中:MMU在TLB中找到匹配的VPN条目,直接获取PFN,组合偏移得到物理地址。耗时约1个CPU周期。
- TLB缺失:MMU需要遍历四级页表进行地址转换,并将结果写入TLB。耗时约10-100个CPU周期。
3.2.3 TLB刷新与上下文切换
当进程切换或页表修改时,TLB中的缓存条目可能失效,需要进行刷新操作:
| 场景 | 刷新方式 | 影响范围 |
|---|---|---|
| 进程上下文切换 | 刷新整个TLB或使用ASID | 所有条目 |
| 页表修改(munmap) | 局部刷新(INVLPG指令) | 特定虚拟地址 |
| 大页启用 | 刷新TLB并重新加载 | 相关条目 |
3.2.4 TLB工作原理SVG图
3.3 大页(HugePage)
大页(HugePage)是Linux内核提供的一种内存管理特性,通过使用更大的页大小(2MB或1GB)来减少页表层级和TLB缺失。对于大内存工作负载,大页可以显著提升性能。
3.3.1 大页的优势
| 指标 | 4KB普通页 | 2MB大页 | 1GB大页 |
|---|---|---|---|
| 页表层级 | 4级(PGD→P4D→PUD→PMT) | 3级(PGD→P4D→PUD) | 2级(PGD→P4D) |
| TLB覆盖范围 | 2MB(512个条目) | 1GB(512个条目) | 512GB(512个条目) |
| 页表大小(1GB内存) | 2MB | 4KB | 8字节 |
| TLB缺失率 | 高 | 低 | 极低 |
3.3.2 大页的配置与使用
大页需要在系统启动时或运行时进行配置:
# 查看当前大页配置
cat /proc/meminfo | grep Huge
# 运行时配置大页数量(2MB大页)
echo 1024 > /proc/sys/vm/nr_hugepages
# 挂载hugetlbfs文件系统
mount -t hugetlbfs hugetlbfs /dev/hugepages
# 使用大页分配内存(C语言示例)
#include <sys/mman.h>
#include <fcntl.h>
int fd = open("/dev/hugepages/test", O_CREAT | O_RDWR, 0755);
void *addr = mmap(NULL, 2 * 1024 * 1024, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
// 使用addr指向的大页内存
3.3.3 大页与普通页对比SVG图
3.4 透明大页(Transparent HugePage)
透明大页(THP)是Linux内核自动管理大页的机制,无需应用程序显式配置。THP在后台自动将符合条件的4KB页面合并为2MB大页,同时支持在内存压力时自动拆分。
3.4.1 THP的工作原理
THP通过内核线程khugepaged在后台扫描内存,将连续的4KB页面合并为大页:
- 扫描阶段:
khugepaged定期扫描进程的虚拟地址空间,查找连续的、可合并的4KB页面。 - 合并阶段:找到符合条件的页面后,分配一个2MB的大页,并将原4KB页面的内容复制到大页中。
- 映射更新:更新页表,将原来的512个PTE替换为1个PUD级别的页表项。
- 拆分阶段:当内存压力增大或页面需要换出时,THP将大页拆分为原始的4KB页面。
3.4.2 THP的配置与监控
# 查看THP状态
cat /sys/kernel/mm/transparent_hugepage/enabled
# 启用THP(always / madvise / never)
echo always > /sys/kernel/mm/transparent_hugepage/enabled
# 查看THP统计信息
cat /proc/meminfo | grep AnonHugePages
# 监控THP合并活动
cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed
3.4.3 THP的优缺点
| 优点 | 缺点 |
|---|---|
| 无需应用修改,透明启用 | 内存碎片化时合并失败率高 |
| 自动管理,降低运维成本 | 合并和拆分操作有CPU开销 |
| 减少TLB缺失,提升性能 | 大页拆分时可能导致延迟抖动 |
| 动态适应内存使用模式 | 某些场景下可能增加内存占用 |
madvise模式,仅对明确标记的内存区域启用THP。