Linux 内存巨页与透明巨页学习

1. linux 内存管理单元介绍

Linux 系统管理内存的最小单元为页,默认页大小为 4KB,可通过 getconf PAGESIZE 查看。

程序访问的是虚拟内存,虚拟地址与物理地址的转换关系记录在页表(Page Table)中。

当 CPU 访问虚拟地址时,会优先查询 TLB(地址转换旁路缓冲存储器),TLB 缓存了常用的虚拟地址→物理地址映射。

如果 TLB 中没有找到(TLB Miss),CPU 会去内存中查询页表,并把新的映射关系缓存到 TLB。

但 TLB 容量很小,能缓存的页表映射条目有限。如果申请内存较大,对应的内存页数量就会非常多,导致 TLB 频繁失效。

这时 CPU 就需要频繁访问内存中的页表查找地址映射,CPU 负载随之升高。

为了降低CPU的负载,就可以通过巨页来增大内存页的大小,通过TLB就能更快的访问到物理内存。

查看系统默认的页大小:

2. 巨页介绍

linux 巨页技术有两个:

  • Huge Pages(静态巨页):

    静态巨页,就是系统启动时就预先分配好、数量固定、位置固定、不会被内核动的大页内存。

    通过大幅减少页表数量、提高 TLB 命中率,显著降低 CPU 地址翻译负担。

  • Transparent Huge Pages (透明巨页)

    THP 透明巨页是内核自动把 4KB 页合并成 2MB 巨页的机制,合并时会卡顿,对应用透明。

    优点是自动优化、无需配置;

    缺点是会造成内存紧缩、CPU 毛刺、IO 波动。

查看是否开启巨页:

查看是否开启透明巨页:

cat /sys/kernel/mm/transparent_hugepage/enabled

csharp 复制代码
[always] madvise never		# 当前状态是开启的
  • always:完全开启状态
  • madvise:只有程序显式要求时才用巨页
  • never: 完全关闭透明巨页

查看是否开启静态巨页:

grep -i huge /proc/meminfo | grep HugePages_Total

csharp 复制代码
HugePages_Total:       0

0 代表未开启,大于0等于分配了多少巨页

开启两种巨页的方式:

开启静态巨页:

复制代码
# 临时开启:
echo 256 > /proc/sys/vm/nr_hugepages   	# 提前分配256个2MB的巨页
# 永久开启:
echo "vm.nr_hugepages=256"  >>/etc/sysctl.conf
sysctl -p		# 立即生效
csharp 复制代码
[root@localhost ~]# cat /proc/meminfo | grep -E 'MemFree|Hugepagesize|HugePages_Total'
MemFree:         1481000 kB				# 未开启巨页前当前剩余内存量
HugePages_Total:       0					# 未开启巨页前巨页数量
Hugepagesize:       2048 kB				# 默认巨页大小
[root@localhost ~]# echo 256 > /proc/sys/vm/nr_hugepages        # 提前分配256个2MB的巨页
[root@localhost ~]# cat /proc/meminfo | grep -E 'MemFree|Hugepagesize|HugePages_Total'
MemFree:          955456 kB			# 开启巨页后的内存剩余量已经减少了
HugePages_Total:     256				# 当前巨页数量
Hugepagesize:       2048 kB			

开启透明巨页:

复制代码
# 临时开启
echo always > /sys/kernel/mm/transparent_hugepage/enabled				# 开启透明巨页
echo always > /sys/kernel/mm/transparent_hugepage/defrag				# 开启透明巨页的内存碎片整理
# 永久开启
cat > /etc/systemd/system/enable-transparent-huge-pages.service <<EOF
[Unit]
Description=Enable Transparent Hugepages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo always | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null && echo always | tee /sys/kernel/mm/transparent_hugepage/defrag > /dev/null'

[Install]
WantedBy=basic.target
EOF
systemctl daemon-reload
# 或者兼容老的系统
cat >> /etc/rc.local <<EOF
echo always > /sys/kernel/mm/transparent_hugepage/enabled
echo always > /sys/kernel/mm/transparent_hugepage/defrag
EOF
chmod +x /etc/rc.local

可以看出系统初始被被内核自动合并为 2MB 巨页的内存为4096 kB,后面执行stress-ng 压测后,被自动合并的内存页明显上升了。

关闭透明巨页:

复制代码
# 临时关闭透明巨页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 永久关闭,如果之前有设置开启的service文件,记得disable掉
cat > /etc/systemd/system/disable-transparent-huge-pages.service <<EOF
[Unit]
Description=Disable Transparent Hugepages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag'

[Install]
WantedBy=basic.target
EOF
systemctl daemon-reload

关闭静态巨页:

复制代码
# 临时关闭:
echo 0 > /proc/sys/vm/nr_hugepages   	# 提前分配256个2MB的巨页
# 永久关闭:
echo "vm.nr_hugepages=0"  >>/etc/sysctl.conf
sysctl -p		# 立即生效

3. 透明巨页和静态巨页的使用场景

  • 透明巨页

    内核自动合并内存,在合并的时候会有卡顿,不适合高IO场景,对延时敏感,不能接受突然卡顿几毫秒~几十毫秒。

    适合对延时不敏感的业务比如:文件服务器,云盘 / 对象存储类服务,日志收集、备份服务器。

  • 静态巨页 HugePages

    内核一次性分配,提前占用内存,不适合小内存服务器,一次性分配内存很小的程序。

    适合申请内存比较多的业务且不经常回收: 虚拟机、redis、mysql。

参考文章:

https://www.jianshu.com/p/391f42f8fb0d

https://mp.weixin.qq.com/s/1CLV53M-1-pomC5Zsnu_dw

https://www.mongodb.com/zh-cn/docs/manual/tutorial/disable-transparent-huge-pages/

https://blog.csdn.net/TiDB_PingCAP/article/details/109227464

https://docs.redhat.com/en/documentation/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-memory-transhuge.html

相关推荐
光电的一只菜鸡6 小时前
ubuntu之坑(二十)——VMware虚拟机系统无法正常进入如何处理
linux·运维·ubuntu
你住过的屋檐8 小时前
【Nginx】linux上安装nginx
linux·运维·nginx
秋饼8 小时前
JDK 27 企业级 AI 服务落地实战:G1 默认、紧凑对象头、后量子 TLS 与 JFR 脱敏全解析
java·ai·技术分享·后端开发
宵时待雨8 小时前
linux笔记归纳17:传输层协议UDP
linux·笔记·udp
卓怡学长9 小时前
w176基于SpringBoot的医院管理系统
java·spring boot·spring·maven·intellij-idea
lemon_sjdk9 小时前
ObjectProperty
java·开发语言·算法
hh9509 小时前
Agent Plan x DeepSeek Harness:Agent 供应链安全与第三方插件审计
java·开发语言·安全·agent plan·adg成都社区·adg社区
吴声子夜歌9 小时前
Java面试——HBase原理及应用
java·面试·hbase
浪兎兎9 小时前
【Java Web】Servlet + JSP 笔记
java·前端·servlet
吴声子夜歌9 小时前
Java面试——ElasticSearch原理及应用
java·面试·es