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

相关推荐
red_redemption2 小时前
自由学习记录(166)
学习
勿忘,瞬间2 小时前
Spring Boot
java·数据库·spring boot
blog.pytool.com2 小时前
Ubuntu + VSCODE +aarch64 +qt +qmake +clangd
linux·qt·ubuntu
CompaqCV2 小时前
OpencvSharp 算子学习教案之 - Cv2.Multiply
学习·c#·opencvsharp算子·opencv教程
SimonKing2 小时前
AI大模型中转平台,无需科学上网就可以使用国外模型
java·后端·程序员
自我意识的多元宇宙2 小时前
二叉树遍历方式代码解读(1递归)
java·数据结构·算法
CompaqCV2 小时前
OpencvSharp 算子学习教案之 - Cv2.Subtract 重载2
学习·c#·opencvsharp算子·opencv教程
学Linux的语莫2 小时前
Linux环境中anaconda 的安装与环境配置
linux·运维·服务器
小陈phd2 小时前
多模态大模型学习笔记(三十五)——OCR全景认知:从字符识别到多模态理解的百年演进
笔记·学习·ocr