Linux transparent huge pages (THP)透明大页

1. Linux 引入透明大页的背景

随着计算需求规模的不断增大,应用程序对内存的需求也越来越大。为了实现虚拟内存管理机制,操作系统对内存实行分页管理。自内存“分页机制”提出之始,内存页面的默认大小便被设置为 4096 字节(4KB),虽然原则上内存页面大小是可配置的,但绝大多数的操作系统实现中仍然采用默认的 4KB 页面。4KB 大小的页面在“分页机制”提出的时候是合理的,因为当时的内存大小不过几十 MB,然而当物理内存容量增长到几 GB 甚至几十 GB 的时候,操作系统仍然以 4KB 大小为页面的基本单位,是否依然合理呢?

在 Linux 操作系统上运行内存需求量较大的应用程序时,由于其采用的默认页面大小为 4KB,因而将会产生较多 TLB Miss 和缺页中断,从而大大影响应用程序的性能。当操作系统以 2MB 甚至更大作为分页的单位时,将会大大减少 TLB Miss 和缺页中断的数量,显著提高应用程序的性能。这也正是 Linux 内核引入大页面支持的直接原因。好处是很明显的,假设应用程序需要 2MB 的内存,如果操作系统以 4KB 作为分页的单位,则需要 512 个页面,进而在 TLB 中需要 512 个表项,同时也需要 512 个页表项,操作系统需要经历至少 512 次 TLB Miss 和 512 次缺页中断才能将 2MB 应用程序空间全部映射到物理内存。然而,当操作系统采用 2MB 作为分页的基本单位时,只需要一次 TLB Miss 和一次缺页中断,就可以为 2MB 的应用程序空间建立虚实映射,并在运行过程中无需再经历 TLB Miss 和缺页中断(假设未发生 TLB 项替换和 Swap)。

为了能以最小的代价实现大页面支持,Linux 操作系统采用了基于 hugetlbfs 特殊文件系统 2M 字节大页面支持。这种采用特殊文件系统形式支持大页面的方式,使得应用程序可以根据需要灵活地选择虚存页面大小,而不会被强制使用 2MB 大页面。

2. 关于 Linux 透明大页的介绍

Linux 透明大页在 RHEL 6 操作系统上默认是开启的,内核都会尽可能的尝试分配大页,如果 mmap 区域自然对齐,那么任何 Linux 进程都会收到 2MB 大小的页面。内核地址空间本身主要使用 huge pages 映射,以便减少来自内核代码的 TLB 压力。

内核尽可能地使用大页来满足内存分配申请,如果没有大页可用(比如没有连续物理内存),内核将会变回 4KB 大小的页面分配策略。

大页也可以交换到 swap 空间,这是通过将巨大的页面分成更小的 4KB 页面来实现的,然后这些页面通常会被交换出去。

但是为了有效地使用 huge pages,内核必须找到足够大的物理连续内存区域来满足请求,并且要正确对齐。为此,添加了一个内核线程,这个线程偶尔会尝试用 huge pages 分配来替换当前使用的较小页面,从而最大限度地提高透明大页的使用率。

对于用户区而言,不需要对应用程序做任何修改,因此称之为透明大页。但是有一些方法可以优化它的使用,对于希望使用 huge pages 的应用程序,使用 posix_memalign(),还可以帮助确保大内存的分配与大页(2MB)边界对齐。

此外,透明大页,只对匿名内存区域启用。有计划增加对 tmpfs 和页面缓存的支持。透明大页可调参数位于 /sys/kernel/mm/redhattransparenthugepage 下的 /sys 树中。

3. 透明大页为什么会有性能问题

透明大页,可以动态地将系统默认内存页块 4KB,交换为 huge pages,在这个过程中,对于操作系统的内存的各种分配活动,都需要各种内存锁,直接影响程序的内存访问性能,这个过程对应用是透明的,在应用层面不可控制,对于专门优化 4KB page 优化的程序来说,可能造成随机的性能下降问题。

在 Redis, MySQL,Oralce 等数据库服务器上,建议关闭透明大页。

4. 查看、开启、关闭透明大页:

4.1 查看透明大页是否开启

Red Hat Enterprise Linux 6.3:
cat /sys/kernel/mm/redhat_transparent_hugepage/enabled

[always] never

CentOS 7.3:
cat /sys/kernel/mm/transparent_hugepage/enabled

[always] madvise never

结果值介绍:

  • always,启用透明大页
  • never,未启用透明大页
  • madvise,表示只在 MADV_HUGEPAGE 标志的 VMA 中使用透明大页

如果 HugePages_Total 返回 0,也表示透明大页禁用了。
grep -i HugePages_Total /proc/meminfo

cat /proc/sys/vm/nr_hugepages
如果上述命令返回 0 也意味着透明大页禁用了。

4.2 启用/禁用透明大页

方法一:

在 /etc/grub.conf 中增加 transparent_hugepage=never

vim /etc/grub.conf


default=0
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux 6 (2.6.32-504.el6.x86_64)
  root (hd0,0)
  kernel /vmlinuz-2.6.32-504.el6.x86_64 ro root=/dev/mapper/VolGroup--LogVol0-LogVol01 rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=VolGroup-LogVol0/LogVol01 rd_LVM_LV=VolGroup-LogVol0/LogVol00 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
  initrd /initramfs-2.6.32-504.el6.x86_64.img
transparent_hugepage=never

方法二:

vim /etc/rc.local

if test -f /sys/kernel/mm/redhat_transparent_hugepage/enabled; then
 echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled
fi

非 Redhat 系统,替换为:
/sys/kernel/mm/transparent_hugepage/enabled

以上方式,需要重启操作系统。

方法三:
echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled

非 Redhat 系统,替换为:
/sys/kernel/mm/transparent_hugepage/enabled

以上方式,不需要重启操作系统。

文章评论

0条评论