slab_unreclaimable是指在Linux内存管理中由slab分配器分配的且被标记为不可回收(unreclaimable)的内存。当不可回收内存占用总内存的比例过高时,将会影响可用内存与系统性能。本文介绍如何排查Alibaba Cloud Linux系统slab_unreclaimable内存占用高的原因。
问题现象
在Linux实例内运行cat /proc/meminfo | grep "SUnreclaim"命令查看SUnreclaim参数指标时,发现内存较大(例如SUnreclaim: 6069340 kB),当该内存超过系统总内存大小的10%时,表示slab_unreclaimable内存占用过高,系统可能会存在slab内存泄露。
可能原因
在Linux内存管理中,slab内存是内核用于高效分配小块内存的一种缓存机制。内核组件或驱动程序通过调用内存分配接口(kmalloc等)向slab分配器申请内存,但是内核组件或驱动程序又没有正确释放内存,这将导致不可用内存越来越多,可用内存越来越少。
排查步骤
- 远程连接待排查问题的Linux实例。 - 具体操作,请参见连接方式概述。 
- 运行以下命令,排查使用 - objects或内存较多,且内存不可回收的slab内存对应的名称。- 查看使用 - objects或内存最多的slab内存信息。- slabtop -s -a- 命令行返回结果中,您可以查看并记录 - OBJ/SLAB列数值较高的slab内存对应的名称(- NAME列)。
- 确认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内存可回收。 
 
- 排查slab_unreclaimable内存占用高的原因。 - 您可以使用crash工具进行静态分析,也可以使用perf工具进行动态分析,排查造成slab内存泄露的原因。本文提供的示例场景中,存在slab泄露的内存名称为 - kmalloc-192。- crash工具静态分析- 运行以下命令,安装crash工具。 - sudo yum install crash -y
- 运行以下命令,安装内核调试工具kernel-debuginfo。 - Alibaba Cloud Linux 3 - sudo yum install -y kernel-debuginfo-<内核版本> --enablerepo=alinux3-plus-debug说明- 内核版本需替换为系统实际的内核版本,通过- uname -r命令查询。
- Alibaba Cloud Linux 2 - sudo yum install kernel-debuginfo -y
 
- 运行以下命令,启动crash工具。 - sudo crash
- 在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列)。
- 在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工具动态分析- 运行以下命令,安装perf工具。 - sudo yum install perf -y
- 运行以下命令,使用perf工具动态获取 - kmalloc-192中没有释放的内存,动态获取数据的时间间隔为200秒。- sudo perf record -a -e kmem:kmalloc --filter 'bytes_alloc == 192' -e kmem:kfree --filter ' ptr != 0' sleep 200
- 在当前目录下,将动态获取的数据打印至临时文件中。 - 本示例中,临时文件名称为testperf.txt。 - sudo perf script > testperf.txt
- 运行以下命令,查看testperf.txt文件内容。 - cat testperf.txt- 您需要手动排查没有空闲内存( - free)的内存信息,然后在Linux内核源代码中手动查询产生slab内存泄露的函数。
 
- 通过crash和perf等工具确定了内存泄露的函数调用路径或者影响的内核数据结构后,建议在内核开发者或专业运维人员指导下确定内存泄露的具体源头,然后解决内存泄露问题。 - 以下是可能用到的一些解决方案,供您参考: - 升级内核或补丁 
- 调整内核参数 
- 重启影响的服务或模块 
- 优化应用程序或驱动 
- 重启系统 
 
相关文档
slab内存泄露会导致实例上运行的业务可用内存变少、内存碎片化,还会引起系统OOM Killer以及系统性能抖动等问题。
- 内存碎片化问题:Linux内存碎片化的应对措施 
- polkit内存泄露问题:如何解决Alibaba Cloud Linux 2中polkit内存泄露问题? 
- 系统OOM Killer问题:出现OOM Killer的原因与解决方案