引言:为什么 THP 在 2026 年依然关键

Transparent Huge Pages(THP)自 Linux 2.6.38(2011)引入以来,始终是 Linux 内存管理中最具争议又不可或缺的特性之一。在 2026 年的今天,随着 AI 推理集群的单节点内存突破数 TB、数据库工作集动辄数百 GB、以及云原生场景下容器密度不断提高,THP 已经从"可选项"变成了影响系统延迟和吞吐的决定性因素。

然而,THP 并非银弹。错误的工作模式会导致内存碎片恶化、khugepaged 占用过高 CPU、数据库出现诡异的性能抖动。本文将从内核源码级原理出发,完整梳理 THP 的工作机制、NUMA 感知策略、khugepaged 参数调优方法,并给出 PostgreSQL、Redis、PyTorch/vLLM、Java 等典型工作负载的生产级配置建议。

1. THP 架构原理:从 4KB 到 2MB/1GB

传统 x86_64 页表采用四级分页结构(PML4 → PDPT → PD → PT),每个页表项(PTE)映射 4KB 页面。当物理内存达到 128GB 时,内核需要维护 3300 万个 PTE,这带来了两类性能开销:

  • TLB 压力:每级页表都有独立的 TLB,4KB 颗粒度下单次页面访问产生 4 次 TLB Miss 的概率极高
  • Page Fault 开销:每个 4KB 页面必须独立触发缺页中断、完成物理页分配

大页(Huge Page)通过让一个 PMD(Page Middle Directory)或 PUD(Page Upper Directory)直接指向大颗粒物理页框,将单次映射从 4KB 提升到 2MB 甚至 1GB,显著减少 TLB Miss 次数。THP 的特殊之处在于它完全自动——无需应用修改代码、无需预分配大页池。

1.1 匿名大页 vs 文件大页

Linux 内核将 THP 分为两类,触发机制完全不同:

  • Anon HugePages:匿名内存区域(堆、栈)的 THP。缺页中断 → 分配 4KB 页面 → 启动 khugepaged 后台线程异步合并相邻页面 → 如果合并成功则拆除零散 PTE 并建立 PMD 大页映射
  • Shmem HugePages:文件映射内存区域(tmpfs、mmap 文件、hugetlbfs)的 THP。系统在缺页时直接分配 2MB 页面(如果可用),不需要异步合并阶段,延迟更低也更可预测

关键是:anon THP 实际上是一个"先返回 4KB 页再慢慢拼凑"的异步过程,这意味着进程启动后的前几百毫秒仍使用普通页,随后逐步升级。shmem THP 则是一次性分配,行为更可预测。

1.2 khugepaged 的工作循环

/sys/kernel/mm/transparent_hugepage/khugepaged 目录控制着内核线程 khugepaged 的行为。该线程运行于 khugepaged_alloc_thread 上下文中,主循环逻辑位于 mm/khugepaged.c。

核心扫描流程如下:

// 简化后的 khugepaged 主循环逻辑
static int khugepaged(void *none)
{
    set_freezable();
    set_user_nice(current, MAX_NICE);  // 优先级最低

    while (!kthread_should_stop()) {
        // 1. 控制扫描频率:默认 10 秒一次睡眠
        khugepaged_scan_sleep_millisecs);

        // 2. 扫描所有匿名 VMA,寻找有足够"已分配"子页面的区域
        for_each_mm(mm) {
            for (vma = mm->mmap; vma; vma = vma->vm_next) {
                // 检查是否需要 khugepaged_scan
                // - VM_NOHUGEPAGE 标记的跳过
                // - MADV_HUGEPAGE 标记的优先
                // - 只在 madvise 模式下需要显式标记
                offset = (vma->vm_pgoff                        
                    
点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部