把transparent_hugepage/enabled从madvise调成always,本想让大页多吃一点,线上 p99 反而涨了两三倍。于是团队记下一条经验:THP 有害,关掉。这条经验错在,它把账算到了大页头上。账其实很好算,而且几乎总是划算:一个 2MB 大页顶 512 个 4KB 页,TLB 覆盖范围涨 512 倍、页表内存省 512 倍——这些收益是真的,几乎从不失手。真正让 THP 在延迟敏感的大内存服务上翻车的,不是大页本身,而是它把「缺页 → buddy 分配 → 回收 → 内存整理」这条平时各干各的慢路径,在一次缺页里串成了一根同步链条。所以该拧的旋钮从来不是always还是madvise,而是defrag和回收水位线;拧错了对象,才是 p99 翻车的真正原因。缺页不是一个局部事件:从硬件页表走查失败说起一个进程访问一个还没落到物理页的虚拟地址,CPU 的 MMU 会自己走一遍页表——x86-64 上是四级(开了 5-level paging 是五级):PGD → PUD → PMD → PTE,每一级是一次依赖性的内存加载,前一级的内容决定下一级去哪读,四次访问严格串行、没法并行掩盖。末级那个 PTE 里如果 present 位是 0,MMU 放弃,产生#PF异常。到这里都还是硬件的事;从这一刻起,内核接手。为什么 TLB 这么金贵,值得为它开大页?因为这四次串行内存访问,即便命中 cache 也是几十