slab_unreclaimable内存为系统不可回收的内存,当其占用总内存的比例过高时,将会影响可用内存与系统性能。本文介绍如何排查Linux slab_unreclaimable内存占用高的原因。

问题现象

在Linux实例内运行cat /proc/meminfo | grep "SUnreclaim"命令查看SUnreclaim参数指标时,发现内存较大(例如SUnreclaim: 6069340 kB),当该内存超过系统总内存大小的10%时,系统可能会存在slab内存泄漏。

可能原因

slab内存是内核组件(或驱动)通过调用kmalloc类接口向伙伴系统申请内存,然后内核组件(或驱动)没有正确释放内存所产生的。实例一旦出现slab内存泄漏,且无法通过kill进程的方式回收内存,则只能通过重启实例解决。

slab内存泄漏会导致实例上运行的业务可用内存变少、内存碎片化,还会引起系统OOM Killer以及系统性能抖动。

解决方案

  1. 远程连接待排查问题的Linux实例。
    具体操作,请参见连接方式概述
  2. 运行以下命令,排查使用objects或内存较多,且内存不可回收的slab内存对应的名称。
    1. 查看使用objects或内存最多的slab内存信息。
      slabtop -s -a

      命令行返回结果中,您可以查看并记录OBJ/SLAB列数值较高的slab内存对应的名称(NAME列)。

    2. 确认slab内存是否为不可回收。

      命令中的<slab NAME>变量需要手动修改为上一步中获取到的OBJ/SLAB列数值较高的slab内存对应的名称。

      cat /sys/kernel/slab/<slab NAME>/reclaim_account
      例如,查看名称为kmalloc-192的slab内存是否为不可回收。
      cat /sys/kernel/slab/kmalloc-192/reclaim_account

      查询结果为0时,表示slab内存不可回收;查询结果为1时,表示slab内存可回收。

  3. 排查slab_unreclaimable内存占用高的原因。

    您可以使用crash工具进行静态分析,也可以使用perf工具进行动态分析,排查造成slab内存泄漏的原因。本文提供的示例场景中,实例对应的操作系统为Alibaba Cloud Linux 2操作系统,存在slab泄漏的内存名称为kmalloc-192

    • 方式一:crash工具静态分析
      1. 运行以下命令,安装crash工具。
        yum install crash -y
      2. 运行以下命令,安装内核调试工具kernel-debuginfo。
        yum install kernel-debuginfo -y
      3. 运行以下命令,启动crash工具。
        sudo crash
      4. 在crash工具内,运行以下命令,查看kmalloc-192内存统计信息。
        kmem -S kmalloc-192
        内存统计信息较多时,您可以设置只显示最后几行(例如10行)信息。
        kmem -S kmalloc-192 | tail -n 10
        命令行的返回结果示例如下:
            SLAB              MEMORY            NODE  TOTAL  ALLOCATED  FREE
          ffffea004c94e780  ffff88132539e000     0     42         29    13
          ffffea004cbef900  ffff88132fbe4000     0     42         40     2
          ffffea000a0e6280  ffff88028398a000     0     42         40     2
          ffffea004bfa8000  ffff8812fea00000     0     42         41     1
          ffffea006842b380  ffff881a10ace000     0     42         41     1
          ffffea0009e7dc80  ffff880279f72000     0     42         34     8
          ffffea004e67ae80  ffff881399eba000     0     42         40     2
          ffffea00b18d6f80  ffff882c635be000     0     42         42     0
        ffff88028398a000统计信息为例,空闲内存较少(FREE列),已分配的内存较多(ALLOCATED列)。
      5. 在crash工具内,运行以下命令,查看ffff88028398a000内存信息。
        rd ffff88028398a000 512 -S

        命令行的返回信息较长,您可以根据命令行提示打印多个页面数据进行分析。例如:

        返回信息中多次出现put_cred_rcu函数时,您可以自行查看Linux内核源码,搜索put_cred_rcu函数。
        void __put_cred(struct cred *cred)
        {
            call_rcu(&cred->rcu, put_cred_rcu);
        }
        查看到put_cred_rcu函数用于异步释放cred,且put_cred_rcu出现在cred的末尾,表示是内核中cred结构体出现了slab内存泄漏。
    • 方式二:perf工具动态分析
      1. 运行以下命令,安装perf工具。
        yum install perf -y
      2. 运行以下命令,使用perf工具动态获取kmalloc-192中没有释放的内存,动态获取数据的时间间隔为200秒。
        perf record -a -e kmem:kmalloc --filter 'bytes_alloc == 192' -e kmem:kfree --filter ' ptr != 0' sleep 200
      3. 在当前目录下,将动态获取的数据打印至临时文件中。
        本示例中,临时文件名称为testperf.txt
        perf script > testperf.txt
      4. 运行以下命令,查看testperf.txt文件内容。
        cat testperf.txt
        您需要手动排查没有空闲内存(free)的内存信息,然后在Linux内核源代码中手动查询产生slab内存泄漏的函数。
        说明 动态获取的信息较多,建议您在专业运维人员的指导下完成问题排查。