1、打开内核slub debug 调试
通过make menuconfig 打开内核配置选项,将以下选项选上。
Kernel hacking->Memory debugging->
CONFIG_SLUB=y
CONFIG_SLUB_DEBUG=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_SLUB_STATS=y
2、Linux 内核内存分配方式
Linux的内存分配方式分为两种,分别是使用页面分配器分配和使用slab分配器分配,其中页面分配器是以page为单位的用来解决大内存块分配的内存分配方式;slab分配器是以Byte为单位的解决小内存快分配的分配方式。在内核中大于1页的内存分配一般使用页面分配器进行分配,小于1页的内存通过slab分配器进行分配。
/proc/meminfo文件下详细描述了内存使用信息,是free命令的详细版,根据各字段含义研究,此文件内容能够体现各部分对于内存使用量的划分;其中分析内存使用情况常看的几个值如下:
MemTotal: 1798684 kB #所有可用的内存大小,物理内存减去预留位和内核使用。
MemFree: 676444 kB #表示系统尚未使用的内存
MemAvailable: 1435360 kB #真正的系统可用内存,除了Memfree还包括缓存buffer、cached和可回收的slab内存
Buffers: 7868 kB #用来给块设备做缓存的内存
Cached: 891544 kB #分配给文件缓冲区的内存
Slab: 61764 kB #内核数据结构缓存
SReclaimable: 31004 kB #可收回slab内存
SUnreclaim: 30760 kB #不可收回slab内存
如果内核存在内存泄漏,则MemAvailable会不断减少,同时SUnreclaim会不断增加
3、SLUB_DEBUG检测内存泄漏
Slub_debug 可以用于定位slab方式管理的内存的泄漏。系统启动后即可查看slab内存申请和释放的次数,slab内存申请和释放记录在/sys/kernel/slab/<leaking_slab>/文件夹中,其中的alloc_calls和free_calls分别为申请和释放内存的次数。通过对比申请和释放的次数从而来定位那些模块存在内存泄漏。当然对于一些系统模块初始化时申请的内存在系统运行时一般是不会释放的。这就会出现只有申请没有释放的情况。这种情况我们不须关心。我们需要重点关注的是那些在打流前后申请和释放次数较多的slab缓存。比如下面的skb的空间也是我们在打流过程中有可能存在内存泄漏的地方
注:红色标记代表申请和释放的次数
对于skb的数据空间在内核中有两种申请方式一种是通过kmalloc申请的,这种方式的申请可以通过在kmalloc-2048中查看。这也是有可能存在内存泄漏的地方。
当然如果skb申请方式为页面片段,那么这种泄漏是通过slab看不出来的。我们也可以通过slabinfo 这个工具更能清晰直观的看出slab内存在一段时间内的变化
红色部分代表当前各个slab缓存的占用大小。如果存在slab内存泄漏该slab对象占用内存会一直增多。此时可以结合上面方法定位具体的slab申请和释放的函数名称。
此外slabinfo 工具还可以定位某个slab 缓存中申请和释放的内存的次数以及调用申请内存的函数如下图查看kamlloc-64 内存申请和释放的次数以及调用申请内存的函数。
例如下面这两幅图是在打流前后30分钟slab内存的变化
打流之前slab 内存
打流30分钟后,清连接slab内存情况
打流停止后,静置设备一段时间slab内存情况
从上面三幅对比图中我们可以得出以下结论:
- 停止打流并清除连接后,kmalloc-128 slab对象占用内存还是很高,而静置一段时间后内存掉下来了,这说明某些模块存在缓存在停止打流后并不会立刻释放内存,而是需要一定的时间超时来释放。
- 最终kmalloc-128 内存停留在26.2M。这跟初始值相差很大,这说明kmalloc-128 slab内存存在内存泄漏。