THP reclaim功能

THP(Transparent Huge Page)reclaim功能用于解决因透明大页THP带来的内存问题(例如OOM)。本文介绍实现THP reclaim功能的接口,以及接口的示例操作说明。

背景信息

Linux操作系统的内存采用分页管理模式,其中的THP是指内核中2 MiB或1 GiB大小的大页面(普通的小页面大小为4 KiB),一般被称为透明大页。基于应用程序使用到的内存范围越来越大,地址转换产生的开销变得不可忽视。因此,当服务器上的应用程序申请内存时,内核会根据进程的实际情况动态分配透明大页,透明大页可以减少TLB(Translation Lookaside Buffer) Miss的出现概率,从而提升应用程序的性能。

THP在带来性能提升的同时,也产生了一定副作用,即可能产生Memory bloating(内存膨胀)问题。该问题产生的原因说明:透明大页申请释放的粒度为2 MiB(即512个小页面),相较于小页面,透明大页更容易产生内存碎片,进而导致内核分配的内存容量大于实际需要的内存容量。

Memory bloating可能引发OOM(Out Of Memory)。例如,一个应用程序实际需要使用2个小页面,即8 KiB内存,但是内核分配了1个透明大页。此时,除去应用程序实际需要的内存(2个小页面),透明大页剩下的内存(510个小页面)大小均为0。最终可能会因RSS(Resident Set Size)内存用量增加而导致OOM。

为解决THP可能引发的内存问题。Alibaba Cloud Linux增加了memcg粒度的THP reclaim功能。在内核回收内存时,该功能会把透明大页拆分为小页面,并将其中的全零页面(zero subpage)回收,从而避免内存的快速膨胀引发OOM。但您需要注意,由于THP reclaim功能会将透明大页拆分为小页面,所以相较于2 MiB大小的透明大页,THP reclaim功能会在一定程度上造成内存性能的回退。

接口说明

实现THP reclaim功能的接口说明,如下表所述:

接口

说明

memory.thp_reclaim

开启或关闭THP reclaim功能。支持以下配置项:

  • reclaim:开启THP reclaim功能。

  • swap:预留配置项,目前暂无实际功能。

  • disable:关闭THP reclaim功能。

THP reclaim功能默认为关闭状态,即接口默认值为disable。

memory.thp_reclaim_stat

查看THP reclaim功能当前的状态。接口内的参数说明如下:

  • queue_length:当前被THP reclaim管理的透明大页数量。

  • split_hugepage:累计拆分的透明大页数量。

  • reclaim_subpage:累计回收的全零页面数量。

该接口的参数值按照NUMA node的顺序(node0、node1)从左到右排列。

memory.thp_reclaim_ctrl

控制THP reclaim功能的触发机制。目前支持以下配置项:

  • threshold:默认值为16。表示当透明大页中的全零页面数量超过该值时,会触发THP reclaim功能。

  • reclaim:用于主动触发THP reclaim功能。

/sys/kernel/mm/transparent_hugepage/reclaim

THP reclaim功能的全局配置接口。支持以下配置项:

  • memcg:该接口的默认配置项。表示每个memory cgroup按照各自的配置开启或关闭THP reclaim,即以每个memory cgroup中的memory.thp_reclaim接口配置为准。

  • reclaim:强制开启所有memory cgroup的THP reclaim功能。

  • swap:预留配置项,目前暂无实际功能。

  • disable:强制关闭所有memory cgroup的THP reclaim功能。

功能限制

仅以下内核版本的Alibaba Cloud Linux镜像支持配置THP reclaim功能:

  • Alibaba Cloud Linux 2:4.19.91-24.al7及以上内核版本。

  • Alibaba Cloud Linux 3:5.10.134-15.al8及以上内核版本。

说明

您可以通过uname -r命令查询镜像的内核版本。

配置THP reclaim功能

本示例操作中,将以创建一个名为test的memory cgroup为例介绍如何配置THP reclaim。

  1. 运行以下命令,创建一个名为test的memory cgroup。

    sudo mkdir /sys/fs/cgroup/memory/test/
  2. 运行以下命令,开启test的THP reclaim功能。

    sudo sh -c 'echo reclaim > /sys/fs/cgroup/memory/test/memory.thp_reclaim'
  3. 运行以下命令,确认test的THP reclaim功能成功开启。

    cat /sys/fs/cgroup/memory/test/memory.thp_reclaim

    返回结果如下图所示,被[]包裹的配置项为生效配置项,[reclaim]表示test的THP reclaim功能已开启。

    image

  4. 运行以下命令,通过THP reclaim功能的全局配置接口强制开启THP reclaim功能。

    sudo sh -c 'echo reclaim > /sys/kernel/mm/transparent_hugepage/reclaim'

    如果您想强制关闭THP reclaim功能,可运行以下命令:

    sudo sh -c 'echo disable > /sys/kernel/mm/transparent_hugepage/reclaim'
    说明

    THP reclaim功能的全局配置接口/sys/kernel/mm/transparent_hugepage/reclaim在设置为强制开启(reclaim)或强制关闭(disable)时,接口生效的优先级会高于各个memory cgroup中的memory.thp_reclaim接口,但不会影响各个memory cgroup中memory.thp_reclaim接口的配置。

  5. 运行以下命令,配置testmemory.thp_reclaim_ctrl接口的threshold配置项。

    sudo sh -c 'echo "threshold 32" >  /sys/fs/cgroup/memory/test/memory.thp_reclaim_ctrl'

    该示例命令表示如果透明大页中的全零页面数量超过32,则会触发THP reclaim的全零页面回收功能。

  6. 主动触发THP reclaim的全零页面回收功能。

    主动触发后,THP reclaim会把所有超过threshold配置的全零页面回收。配置项reclaim存在以下配置方式:

    说明

    该配置项的调用方式为同步调用,并且为只写配置项,即您只能向memory.thp_reclaim_ctrl接口写入reclaim以主动触发THP reclaim的全零页面回收功能,但不能通过cat命令查看到reclaim配置项。

    • 运行以下命令,会主动触发当前memory cgroup的THP reclaim的全零页面回收功能。

      sudo sh -c 'echo "reclaim 1" >  /sys/fs/cgroup/memory/test/memory.thp_reclaim_ctrl'
    • 运行以下命令,会主动递归触发当前memory cgroup以及该cgroup下所有子cgroup的THP reclaim的全零页面回收功能。

      sudo sh -c 'echo "reclaim 2" >  /sys/fs/cgroup/memory/test/memory.thp_reclaim_ctrl'

      除了通过reclaim主动触发THP reclaim的全零页面回收功能。THP reclaim还会伴随内存回收而触发:

      • 内存出现OOM时,会触发THP reclaim的全零页面回收功能。

      • 当memory cgroup触发memory后台异步回收时,会触发THP reclaim的全零页面回收功能。关于memory后台异步回收的更多信息,请参见Memcg后台异步回收

  7. 运行以下命令,查看test的THP reclaim功能状态。

    cat /sys/fs/cgroup/memory/test/memory.thp_reclaim_stat

    返回结果示例如下:

    queue_length        14
    split_hugepage     523
    reclaim_subpage 256207

    该结果表示:

    • queue_length表示THP reclaim管理的透明大页数量为14。

    • split_hugepage表示累计拆分的透明大页数量为523。

    • reclaim_subpage表示累计回收的全零页面数量为256207。

测试THP reclaim功能效果

本节基于C语言提供了进程申请透明大页的代码测试样例。您可以通过以下测试样例,查看到THP reclaim功能在开启与关闭时的区别。

  1. 运行以下命令,为内存使用量限制接口memory.limit_in_bytes设置1 GiB的限制。

    sudo sh -c 'echo 1G > /sys/fs/cgroup/memory/test/memory.limit_in_bytes'

    设置后,您可以运行以下命令查看memory.limit_in_bytes接口的值。

    cat /sys/fs/cgroup/memory/test/memory.limit_in_bytes

    查看结果如下图所示:

    image

  2. 运行以下命令,关闭memcg后台异步回收功能。

    关于memcg后台异步回收的更多信息,请参见Memcg后台异步回收

    sudo sh -c 'echo 0 > /sys/fs/cgroup/memory/test/memory.wmark_ratio'
  3. 分别在开启或关闭THP reclaim功能的前提下,运行以下命令对C语言代码进行测试,并查看测试结果。

    gcc -o test <test.c>

    其中,<test.c>的代码示例如下,您可以根据实际需求替换。

    // 申请1 G内存(即512个透明大页),其中10个透明大页包含部分全零页面。
    #include <stdlib.h>  // For posix_memalign
    #include <string.h>  // For memset
    #include <unistd.h>  // For pause
    
    #define HUGEPAGE_SIZE 4096 * 512
    int main()
    {
            int i, thp = 512;
            char *addr;
            posix_memalign((void **)&addr, HUGEPAGE_SIZE, HUGEPAGE_SIZE * thp);
    
            for (i = 0; i < 10; i++) {
                    memset(addr, 0xc, HUGEPAGE_SIZE >> 1);
                    addr += HUGEPAGE_SIZE;
            }
    
            for (; i < thp; i++) {
                    memset(addr, 0xc, HUGEPAGE_SIZE);
                    addr += HUGEPAGE_SIZE;
            }
    
            pause();
            return 0;
    }

    在测试过程中,您可以在另一台终端通过dmesg -wH命令同步监控系统是否发生OOM事件和内存使用情况。测试结果根据THP reclaim功能的开启状态有所不同:

    • THP reclaim功能开启:进程申请透明大页过程中,THP reclaim会把前序申请的透明大页拆分为小页,并回收其中的全零页面,从而减少内存的使用量,最终不会发生OOM。

    • THP reclaim功能关闭:系统不会主动拆分和回收全零页面,最终发生OOM,您将看到内核输出关于内存不足的日志信息,包括可能被杀死的进程详情。

相关文档