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

【操作系统百科】HugeTLB 与 THP

文章导航

分类入口
os
标签入口
#huge-page#thp#hugepage#khugepaged#madvise

目录

D-32 讲了 TLB miss 代价巨大。大页让一条 TLB 项覆盖 2MB 或 1GB——TLB miss 率可降 70-90%。但 Linux 的两种大页机制在工程上各有陷阱。

一、先看图

flowchart LR
    APP[应用 mmap] --> TYPE{大页类型}
    TYPE -->|HugeTLB| POOL[HugeTLB pool<br/>预留 2M/1G]
    TYPE -->|THP| KHUGE[khugepaged<br/>后台合并]
    TYPE -->|madvise| MADV[仅标记区域<br/>尝试 THP]
    POOL --> TLB[TLB: 1 entry = 2M/1G]
    KHUGE --> TLB
    MADV --> TLB
    KHUGE -.合并失败.-> COMPACT[compaction<br/>碎片整理]
    COMPACT -.仍失败.-> FALL[fallback 4K]
    classDef ok fill:#3fb95022,stroke:#3fb950,color:#adbac7;
    classDef warn fill:#f0883e22,stroke:#f0883e,color:#adbac7;
    class POOL,TLB ok
    class COMPACT,FALL warn

二、HugeTLB(静态大页)

2.1 基础

在系统启动或运行时预留固定数量的 2MB/1GB 页:

# 启动参数
hugepagesz=2M hugepages=1024    # 预留 1024 × 2MB = 2GB
hugepagesz=1G hugepages=4       # 预留 4 × 1GB = 4GB

# 运行时
echo 1024 > /proc/sys/vm/nr_hugepages         # 2MB
echo 4 > /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages  # 1GB

2.2 使用

// mmap
void *p = mmap(NULL, size, PROT_READ|PROT_WRITE,
    MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0);

// 或 hugetlbfs
mount -t hugetlbfs none /mnt/huge
fd = open("/mnt/huge/myfile", O_CREAT|O_RDWR);
p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

2.3 优缺点

优点:

缺点:

DPDK、QEMU/KVM、Oracle DB 是 HugeTLB 的主力用户。

三、THP(Transparent Huge Pages)

3.1 思路

自动把 4K 页合并成 2M(不需要应用改代码)。

3.2 三种模式

cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never

3.3 khugepaged

后台内核线程,扫描进程页表,把 512 个连续 4K 页合并成一个 2M THP。

cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_to_scan   # 4096
cat /sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs  # 10000

3.4 defrag

缺页时如果没有 2M 连续页,要不要做 compaction?

cat /sys/kernel/mm/transparent_hugepage/defrag
# [always] defer defer+madvise madvise never

四、THP 为什么被数据库关掉

4.1 延迟毛刺

4.2 内存膨胀

THP 按 2M 粒度分配——即使只用 1 个 4K 字节也要 2M → 内部碎片。

4.3 Redis / MongoDB / PostgreSQL 都建议

echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

4.4 何时适合 THP

五、file-backed THP(5.4+)

不只匿名页——文件页也能用 THP:

好处:大文件顺序读效率提升。但生产还在渐进推广。

六、THP 与 NUMA

THP 分配需要连续 2M 物理页——当某个 node 碎片化时可能分配到远端 node,反而增加 NUMA miss。

/sys/kernel/mm/transparent_hugepage/khugepaged/max_ptes_none 控制合并时允许多少空 PTE(越大越容易合并但浪费越多)。

七、观察

# THP 统计
cat /proc/meminfo | grep -i huge
# AnonHugePages: 2048000 kB
# HugePages_Total: 1024
# HugePages_Free:  200

# khugepaged 效果
cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed

# compaction 统计
cat /proc/vmstat | grep compact
# compact_stall compact_success compact_fail

compact_stall 持续增长 = THP 触发的 compaction 在拖慢系统。

八、调优建议

场景 建议
通用服务器 THP=madvise, defrag=defer+madvise
数据库 THP=never
JVM 大堆 THP=madvise + MADV_HUGEPAGE
DPDK/KVM HugeTLB 预留 2M/1G
HPC THP=always 或 HugeTLB

九、2M vs 1G

1G 的好处:一条 TLB 覆盖整个 GB——对几百 GB 的 VM 或 DB 能进一步减少 TLB miss。

十、常见问题

A:HugePages_Free 不等于可用 预留页可能被 cgroup 限制。看 HugePages_Rsvd

B:THP=always + Redis = 延迟飙升 经典踩坑。改 never + 重启 Redis。

C:1G hugepage 分配失败 启动后内存碎片化无法凑 1G 连续。只能 boot 参数预留。

D:容器内看不到 hugepages 需要 cgroup hugetlb 控制器 + 设备挂载。

十一、小结


至此子系列 D(虚拟内存)完结,共 12 篇(29-40)。下一子系列 E:内核内存分配器(6 篇,41-46)将讲 buddy 系统、SLUB、kmalloc、vmalloc、mempool、用户态分配器。


参考文献

工具


上一篇NUMA 内存 下一篇Buddy 系统

同主题继续阅读

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

2026-04-23 · os

【操作系统百科】TLB 工程

TLB 容量有限,shootdown 在多核下常是扩展性终点。本文讲 TLB 层级、PCID/ASID 命中、shootdown 代价、INVLPGB 与 arm64 TLBI 广播、lazy tlb、huge page 对 TLB 的放大效应。

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 集成。


By .