Linux 巨型页(HugePages)

1. 什么是巨型页

页面是Linux管理内存的基本单位,一般为4KB。如果程序运行时,需要大量的内存,就会产生非常多的TLB未命中和缺页异常,4KB的尺寸显然称为程序的瓶颈。如果直接修改系统默认页面大小,那么系统中其他程序运行时,很可能又会造成内存浪费。所以,Linux引入了巨型页,这种巨型页允许管理远大于4k的大页面,默认是2M,相当于512个普通页面。简而言之,通过启用大页面,系统可以处理更少的页面表,因此访问/维护它们的开销也更少!

巨型页的应用集中在对内存需求大的领域,比如数据库、虚拟机等系统中。

2. 原理

回顾下页面寻址,详细内容可参见 《页表》 。如下图

 

为了加快速度,采用了分段机制映射,如下图,而在2级转换目录之后,可以直接指向2MB的巨型页。在1级转换目录之后更是可以指向1GB的超大巨型页。

Linux 巨型页(HugePages)_第1张图片

 

3. 巨型页的实现方式

巨型页的实现需要CPU和内核的支持,在2中讲了通过块描述符来支持巨型页的方式,就是说一个块描述符就可以指向一个巨型页,不过粒度太粗了。这里讲一下另一种实现方式,通过页/块描述符的连续位组成一个集合,而用这个集合表示一个巨型页。也就是说,进程申请了一个巨型页,那么内核会申请n页连续的物业内存,当然这些也会被缓存到TLB中。具体说,每个页表项中都有一个连续标志位,当MMU(内存管理单元),访问其中任意一个页表项时,就会把N个页表项合并,并且填充到TLB中。这种方式就可以支持更多尺寸的页表(注意1级页表的块描述符不能使用连续位,也就是说页面4K时,不支持大于1GB的巨型页)

举两个例子

如果2级转换表中的块描述符支持16个连续块(一块2M),那么它就可以支持16*2MB=32MB的巨型页。

如果32级转换表中的页描述符支持16个连续页(一页4K),那么它就可以支持16*4KB=64KB的巨型页。

 

4. 巨型页池

每个巨型页的长度并不总是相同尺寸的。比如x86 CPU具有支持4K和2M页面,而ia64支持4K,8K,64K, 256K等。这些都是可以同时存在的。而内核通过巨型页池(数组)来管理这些巨型页。相关源码如下

mm/hugetlb.c

int hugepages_treat_as_movable;// 巨型页池的数量

int hugetlb_max_hstate __read_mostly;
unsigned int default_hstate_idx;// 巨型页池的索引
struct hstate hstates[HUGE_MAX_HSTATE];//巨型页池数组

从内存管理的角度来看,巨型页分两种

  • 永久巨型页,提前分配好的,保留的,进程从巨型页池中获取,释放则归还到巨型页池中。
  • 临时巨型页,但永久巨型页不够用时,分配临时巨型页。进程释放临时巨型页时,直接释放到页分配器。不过,如果系统运行时间很长,容易出现碎片话,临时巨型页可能会分配失败。

内核中有一个hugetlb的模块负责巨型页的管理,而hugetlbfs基于hugetlb,在加载时会向内核注册hugetlbfd文件系统,结果允许保存到hugetlbfs_vfs中。

/proc/sys/vm/nr_overcommit_hugepages 临时巨型页的数量

/proc/sys/nr_hugepages 巨型页池中永久巨型页的数量

 

5. 相关命令

5.1 查看巨型页信息

grep Huge /proc/meminfo

其中,

  • HugePages_Total表示大页面池的大小
  • HugePages_Free表示池中尚未分配的大页面数
  • HugePages_Rsvd表示保留的大页面数,这些页面尚未分配
  • HugePages_Surp是“盈余”页面,如果默认配置100,现在修改为80,则会显示20

 

5.2 HugePage 配置

配置有多种方式,可以修改启动项重新启动机器,也可以修改内核参数。这里以后者为例。

5.2.1 修改文件

root@VM-0-16-ubuntu:/home/ubuntu# sudo echo  10 > /proc/sys/vm/nr_hugepages
root@VM-0-16-ubuntu:/home/ubuntu# grep Huge /proc/meminfo
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
HugePages_Total:      10
HugePages_Free:       10
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
root@VM-0-16-ubuntu:/home/ubuntu# sudo echo  100 > /proc/sys/vm/nr_hugepages
root@VM-0-16-ubuntu:/home/ubuntu# grep Huge /proc/meminfo
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
HugePages_Total:     100
HugePages_Free:      100
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

 

5.2.2 修改sysctl.conf

添加配置项目 vm.nr_hugepages=128

root@VM-0-16-ubuntu:/home/ubuntu# echo  "vm.nr_hugepages=128 ">> /etc/sysctl.conf
root@VM-0-16-ubuntu:/home/ubuntu# sysctl -p
kernel.sysrq = 1
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0
kernel.printk = 5
vm.nr_hugepages = 128
root@VM-0-16-ubuntu:/home/ubuntu# grep Huge /proc/meminfo
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
HugePages_Total:     128
HugePages_Free:      128
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB

5.2.3 启用和关闭hugepage

root@VM-0-16-ubuntu:/home/ubuntu#  cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never

启用就是 [always] madvise never

不启用时 always madvise [never]

注意方括号的位置

 

参考

[0] http://oenhan.com/linux-kernel-khugepaged

[1] https://de5uebd9xnqr0.cloudfront.net/services/what-is-huge-pages-in-linux/

[2] https://ke.qq.com/webcourse/3294666/103425320

 

你可能感兴趣的:(009-Linux内核,002-操作系统,内核,巨型页,hugepages,hugepage,TLB)