Transparent Huge Pages
1.背景:为什么需要大页
现代操作系统通过虚拟内存管理进程地址空间。应用看到的是连续的虚拟地址,内核和 MMU 负责把虚拟地址映射到物理内存页。
常规内存页通常是 4KB。假设一个进程使用 8GB 内存:
Plain Text
8GB / 4KB = 2,097,152 个页
这意味着系统需要维护大量页表项,CPU 在访问内存时也需要频繁做虚拟地址到物理地址的转换。
为减少转换开销,CPU 使用 TLB(Translation Lookaside Buffer)缓存近期的地址映射。但 TLB 容量有限,页越小,同样内存规模需要的页表项越多,TLB miss 的概率越高。
大页的目标就是:用更大的页映射同样的内存区域,减少页表项数量,降低 TLB miss。
常见页大小:
| 类型 | 常见大小 | 特点 |
| 普通页 | 4KB | 默认内存页,粒度细,碎片压力小 |
| Huge Page | 2MB | 常见大页,减少页表和 TLB 压力 |
| Huge Page | 1GB | 更大粒度,通常用于特殊高性能场景 |
示意:

2.大页的两种使用方式
Linux 中常见的大页机制有两类:
- 显式 HugeTLB
- Transparent Huge Pages,简称 THP
2.1 显式 HugeTLB
显式 HugeTLB 需要提前在系统中预留大页,应用也需要明确申请使用。
特点:
- 行为确定
- 需要预留内存
- 使用成本较高
- 不会被普通内存分配自动占用
- 适合数据库、DPDK、HPC、低延迟系统等场景
典型查看方式:
cat /proc/meminfo | grep -i huge
典型 JVM 参数:
-XX:+UseLargePages
2.2 Transparent Huge Pages
THP 的目标是让应用无需显式改造,也能自动使用大页。
它主要针对匿名内存,比如进程 heap、mmap 匿名映射等。内核会尝试把连续的 4KB 页合并成 2MB 大页,或者在分配内存时直接分配 2MB 大页。
特点:
- 对应用透明
- 不需要应用显式申请 HugeTLB
- 降低使用门槛
- 自动决策不一定准确
- 可能引入内存规整、延迟抖动和内存碎片问题
THP 的核心问题不在“大页”,而在“自动”。
3.THP 的工作模式
THP 常见配置位于:
/sys/kernel/mm/transparent_hugepage/enabled
查看:
cat /sys/kernel/mm/transparent_hugepage/enabled
常见输出:
[always] madvise never
含义:
| 模式 | 含义 |
| always | 内核尽量自动为匿名内存使用 THP |
| madvise | 只有应用通过 madvise 声明适合大页的区域才使用 THP |
| never | 禁用 THP |
Linux Kernel 官方文档明确提供了 always、madvise、never 三种控制方式,并说明可以把 THP 限制在 MADV_HUGEPAGE 标记的内存区域,以避免无差别启用带来的额外内存消耗风险。参考:Transparent Hugepage Support - Linux Kernel Documentation。
Alibaba Cloud Linux 官方文档也对 madvise 做了相同定义:只有通过 madvise() 系统调用并设置 MADV_HUGEPAGE 标记的内存区域才开启 THP。这个定义可以作为生产中推荐 madvise 而不是 always 的补充依据。参考:Alibaba Cloud Linux 系统中与透明大页 THP 相关的性能调优方法。
还有一个常见配置:
/sys/kernel/mm/transparent_hugepage/defrag
它影响 THP 分配失败时是否进行内存规整。
4.THP 的核心机制
THP 通常通过两条路径生效:
- 分配时直接使用大页
- 后台线程把普通页合并为大页
4.1 分配时直接使用大页
当进程申请内存并触发缺页异常时,内核可能尝试直接分配一个 2MB 大页。
如果系统有连续的 2MB 物理内存,分配较顺利。
如果没有连续 2MB 物理内存,内核可能:
-
- 回退到 4KB 普通页
- 触发内存规整
- 根据 defrag 策略产生同步等待
示意:

4.2 khugepaged 后台合并
Linux 内核中有一个后台线程 khugepaged,会扫描符合条件的内存区域,把多个连续的 4KB 页合并成 2MB THP。
这个过程称为 collapse。
示意:
2MB / 4KB = 512,因此一个 2MB THP 对应 512 个普通页。
5.THP 的收益
THP 主要收益来自地址转换成本降低。
5.1 减少页表项
大页可以显著减少页表项数量。页表更小,页表遍历成本更低。
5.2 降低 TLB miss
TLB 缓存的是虚拟页到物理页的映射。页越大,一个 TLB entry 覆盖的内存范围越大。
1 个 4KB 页 TLB entry 覆盖 4KB
1 个 2MB 页 TLB entry 覆盖 2MB
这对大内存、顺序访问、热点区域稳定的程序更有价值。
5.3 减少 page fault 次数
对于大块连续内存分配,使用 THP 后,可能减少部分缺页处理次数。
6.THP 的风险
THP 的风险主要来自自动分配、自动合并和大页对连续物理内存的要求。
6.1 内存碎片
THP 需要连续的 2MB 物理内存。系统运行一段时间后,物理内存可能被不同生命周期的页切碎。
示意:
理想状态: [---------------- 2MB 连续空闲内存 ----------------] 碎片状态: [空闲][已用][空闲][已用][空闲][已用][空闲][已用]
碎片状态下,即使总空闲内存足够,也可能没有连续 2MB 空间。
6.2 内存规整带来的延迟抖动
为了获得连续 2MB 空间,内核可能触发 compaction,把可移动页搬到一起,整理出连续空闲空间。
这会消耗 CPU,并可能造成请求延迟抖动。
对低延迟服务来说,P99/P999 受影响的风险比平均吞吐更重要。
6.3 内存浪费
如果应用只使用了大页中的一小部分,也可能导致实际内存占用放大。
例如,一个 2MB THP 中只有少量数据是活跃的,但整个大页仍被视为占用。
Alibaba Cloud Linux 文档把这类问题称为 Memory bloating。典型例子是应用实际只需要少量 4KB 小页,但内核分配了一个 2MB THP,剩余大量全零子页也会被计入 RSS,从而可能导致容器或 cgroup 视角下内存占用膨胀,严重时触发 OOM。参考:THP reclaim 功能。
6.4 自动决策不理解业务语义
内核只能根据内存区域、访问模式和系统状态做启发式判断。它不知道这块内存是不是长期热点,也不知道业务是否更关注吞吐还是尾延迟。
这也是生产环境中经常不建议使用 always 的核心原因。
6.5 THP reclaim
在 Alibaba Cloud Linux 中,THP reclaim 是一个用于缓解 THP memory bloating 的机制。它可以在 memcg 粒度把透明大页拆分为小页,并回收其中的全零页面,从而降低 RSS 膨胀引发 OOM 的风险。
需要注意,THP reclaim 的代价是会把 2MB THP 拆成 4KB 小页,因此可能带来一定内存访问性能回退。它更像是对 THP 副作用的缓解机制,而不是证明 THP 可以无风险全局开启。
相关接口包括:
/sys/kernel/mm/transparent_hugepage/reclaim
memory.thp_reclaim
memory.thp_reclaim_stat
memory.thp_reclaim_ctrl
其中 memory.thp_reclaim_stat 可观察:
queue_length
split_hugepage
reclaim_subpage
7.THP 如何影响 JVM
JVM 是 THP 讨论中非常典型的场景。原因是 Java 应用通常有较大的 heap,且 heap 是匿名内存,容易成为 THP 作用对象。
7.1 JVM 内存结构
JVM 进程内存大致包括:
- Java Heap
- Metaspace
- Code Cache
- Thread Stack
- Direct Buffer
- GC 相关结构
- JVM Native 内存
示意:
THP 最常影响的是 Java Heap,因为 heap 通常较大、连续、匿名映射。
观察 JVM 内存时,需要区分 JVM 内部视角和容器外部视角。
例如,JVM 内部通过 heap、non-heap、NMT 或 GC 日志看到的内存占用可能是 1GB,但从 Pod 或 cgroup 外部看到的 RSS / working set 可能是 1.5GB。这不一定表示 JVM 统计错误,而是统计口径不同。
常见差异来源:
- JVM 内部统计通常更关注 Java Heap、Metaspace、Code Cache、Direct Buffer、线程等 JVM 可归因内存。
- Pod / cgroup 视角统计的是整个进程组对内核资源的实际占用,通常包括 Java Heap、JVM native 内存、线程栈、JNI/native library、allocator 缓存、页表、mmap 区域、文件映射、page cache 相关计量等。
- JVM allocator 或 native library 释放内存后,内存可能仍被进程 allocator 缓存,未立即归还给 OS。
- THP 使用 2MB 粒度的大页后,外部 RSS 或 cgroup 口径可能更容易看到按大页粒度体现的占用变化。
因此,排查 JVM 内存问题时不能只看 JVM 内部指标,也不能只看 Pod RSS。更合理的方式是把两类口径放在一起看:
JVM 内部视角:heap / non-heap / NMT / GC log
Pod 外部视角:container_memory_working_set_bytes / RSS / cgroup memory.current
如果二者差距较大,优先进一步拆分 native memory、Direct Buffer、线程栈、mmap、allocator 缓存和 THP 使用情况。
7.2 JVM 使用 THP 的方式
JVM 中和大页相关的参数常见有两类:
-XX:+UseTransparentHugePages
以及:
-XX:+UseLargePages
二者含义不同:
| JVM 参数 | 对应机制 | 特点 |
| -XX:+UseTransparentHugePages | THP | 依赖内核 THP,通常配合 madvise |
| -XX:+UseLargePages | 显式 HugeTLB | 需要系统预留 hugepages,确定性更强 |
推荐理解:
UseTransparentHugePages = JVM 告诉内核:这些区域可以考虑用 THP
UseLargePages = JVM 明确申请系统预留的大页
7.3 为什么 JVM 自己的 THP 开关通常优于 kernel always
如果内核 THP 是 always,内核会尽量对所有符合条件的匿名内存自动使用 THP。
如果内核 THP 是 madvise,再由 JVM 使用:
-XX:+UseTransparentHugePages
那么 THP 的影响范围会收敛到 JVM 主动声明的内存区域。
示意:

因此,JVM 自己的 THP 开关通常比 kernel always 更可控。
但它并不消除 THP 的全部风险。只要最终使用的是 THP,就仍然可能受 compaction、collapse、split、NUMA、内存碎片等因素影响。
7.4 对 GC 的影响
THP 对 GC 的影响不是单向的。
可能收益:
- 大 heap 场景下减少 TLB miss
- 降低页表开销
- 对吞吐型 GC 可能有正收益
可能风险:
- GC 期间访问大量内存时,大页 split 或 page fault 可能带来抖动
- 内存规整可能影响应用线程或 GC 线程延迟
- 对低延迟 GC,尾延迟风险需要重点验证
不同 GC 的敏感点:
| GC | 关注点 |
| Parallel GC | 吞吐优先,可能更容易从大页中受益 |
| G1 GC | 大 heap 常见,需要关注 pause time 和 remembered set 行为 |
| ZGC/Shenandoah | 低延迟优先,更需要关注尾延迟和内存映射行为 |
结论不是“JVM 应该开 THP”或“JVM 不应该开 THP”,而是:
JVM 使用 THP 必须结合 GC、heap 大小、访问模式、延迟目标和压测数据判断。
8.K8s 节点上的 THP 策略
对于通用 Kubernetes 节点,通常不建议使用 THP always。
原因:
- Pod 生命周期复杂
- 多进程、多语言、多内存模型混部
- 内存申请释放频繁
- 节点资源共享
- 自动 THP 决策影响面过大
- 尾延迟问题排查困难
更保守的生产策略:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
或者:
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
推荐 madvise 的依据是:Linux Kernel 文档说明 madvise 可以把 THP 使用范围限制在应用显式声明的区域;madvise(2) 手册也说明 MADV_HUGEPAGE 适用于开发者明确知道访问模式、且不会增加内存占用风险的内存区域。参考:madvise(2) - Linux manual page。
Alibaba Cloud Linux 的 THP 调优文档也指出,THP 对系统性能的影响不能一概而论,需要根据业务、系统和应用实际情况调整;对于数据库、大量延迟敏感应用、大量短生命周期内存分配等场景,如果稳定性比性能更重要,建议关闭 THP。参考:Alibaba Cloud Linux 系统中与透明大页 THP 相关的性能调优方法。
如果某些 workload 确实需要大页,优先考虑:
- 独立 node pool
- node label / taint 隔离
- K8s HugePages 显式资源
- JVM 或应用显式参数
- 压测验证
K8s 显式 HugePages 示例:
YAML resources: requests: hugepages-2Mi: 1Gi memory: 2Gi limits: hugepages-2Mi: 1Gi memory: 2Gi
Kubernetes 官方文档支持把 HugePages 作为可调度资源显式声明,并要求节点预先分配 huge pages;这更符合 K8s 的资源隔离和可调度模型。参考:Manage HugePages - Kubernetes Documentation。
9.如何观察 THP
9.1 查看系统配置
cat /sys/kernel/mm/transparent_hugepage/enabled
cat /sys/kernel/mm/transparent_hugepage/defrag
9.2 查看系统 THP 使用情况
grep -i huge /proc/meminfo
重点关注:
Plain Text
AnonHugePages
ShmemHugePages
FileHugePages
HugePages_Total
HugePages_Free
Hugepagesize
其中 AnonHugePages 通常可以反映匿名内存中 THP 使用情况。
9.3 查看进程级 THP
cat /proc/<pid>/smaps | grep -i AnonHugePages
或者汇总:
grep -i AnonHugePages /proc/<pid>/smaps | awk '{sum += $2} END {print sum " kB"}'
9.4 查看 khugepaged 指标
不同内核版本路径可能略有差异,常见位置:
/sys/kernel/mm/transparent_hugepage/khugepaged/
可查看:
ls /sys/kernel/mm/transparent_hugepage/khugepaged/
常见指标包括:
- pages_collapsed
- full_scans
- scan_sleep_millisecs
- alloc_sleep_millisecs
10.压测建议
THP 是否有收益,不能只看平均吞吐。
建议至少对比三组:
- THP never
- THP madvise
- THP madvise + JVM -XX:+UseTransparentHugePages
如果是专用节点,也可以加一组:
- THP always
关键指标:
| 指标 | 说明 |
| 平均吞吐 | 是否真的提升 |
| P95/P99/P999 延迟 | 是否引入尾延迟抖动 |
| CPU 使用率 | 是否减少地址转换开销,或增加 compaction 开销 |
| GC pause | JVM 场景必须关注 |
| page fault | 是否出现异常波动 |
| AnonHugePages | THP 是否真的生效 |
| compact_stall | 是否发生内存规整等待 |
| Broker 网络和磁盘指标 | 避免误把 IO 瓶颈归因到 THP |
Linux VM 统计中可以关注:
cat /proc/vmstat | grep -E 'compact|thp'
常见指标:
thp_fault_alloc
thp_fault_fallback
thp_collapse_alloc
thp_collapse_alloc_failed
compact_stall
compact_fail
compact_success
11.推荐结论
11.1 通用结论
THP 的价值在于降低页表和 TLB 成本,适合大内存、访问模式稳定、吞吐敏感的场景。
THP 的风险在于它是自动机制,内核不能准确理解业务内存语义,可能引入内存规整、碎片、内存浪费和尾延迟抖动。
11.2 生产建议
| 场景 | 建议 |
| 普通 K8s 节点 | never 或 madvise |
| 混部微服务节点 | 避免 always |
| JVM 普通业务服务 | 默认不开,压测后决定 |
| 数据库 / DPDK / HPC | 优先考虑显式 HugeTLB |
| 极致低延迟服务 | 谨慎使用 THP,重点验证 P99/P999 |
Red Hat 官方性能调优文档也指出,THP 自动化了 huge page 的创建、管理和使用,但并不适合所有 workload,并明确提到 THP 不推荐用于数据库 workload。参考:Huge Pages and Transparent Huge Pages - Red Hat Documentation。
Alibaba Cloud Linux 官方文档进一步补充了几个生产风险点:defrag=always 可能在内存紧张时触发同步直接回收和直接整理;khugepaged 合并大页时会在内存路径中加锁;如果在错误时间触发扫描和转换,可能影响内存敏感型应用。该文档也建议在部分场景下评估 defer+madvise,在性能和平稳性之间折中。参考:Alibaba Cloud Linux 系统中与透明大页 THP 相关的性能调优方法。
11.3 一句话总结
大页本身不是问题,问题是自动大页决策是否真的理解业务场景。对于通用 K8s 节点,THP always通常不值得;对于数据库、DPDK、HPC 等专用 workload,可以通过隔离节点、显式声明和压测验证来使用大页能力
12.为什么小白集群没有此问题
Alibaba Cloud Linux 3(基于Anolis OS)与 Alibaba Cloud Linux 2(基于CentOS 7)在透明大页(THP, Transparent Huge Pages)的默认行为上存在以下主要区别:
1.默认启用状态:
-
- Alibaba Cloud Linux 2:默认启用 THP([always] madvise never),适用于通用场景,但对延迟敏感型应用(如数据库)可能产生性能影响。
- Alibaba Cloud Linux 3:默认改为 madvise 模式(always [madvise] never),仅对明确使用 MADV_HUGEPAGE 的进程启用 THP,减少对未优化应用的干扰。
2.配置路径一致性:
-
- 两者均通过 /sys/kernel/mm/transparent_hugepage/enabled 控制 THP 状态,命令操作方式相同。
3.推荐操作:
-
- 若运行 Redis、MongoDB 等数据库,建议在两系统中均显式关闭 THP:
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
-
- 永久生效需添加到 /etc/rc.local 或创建 systemd 服务。
可通过以下命令检查当前 THP 状态:
cat /sys/kernel/mm/transparent_hugepage/enabled

浙公网安备 33010602011771号