Linux Kernel模块内存泄露分析

2020-09-09  本文已影响0人  Nothing_655f

1、通过free 看 剩余内存

# free                                          
 total        used        free      shared     buffers
Mem:       2065866752  1268113408   797753344           0     9060352
-/+ buffers/cache:     1259053056   806813696
Swap:       524283904           0   524283904

假如通过“Free”查看内存几乎耗尽,但通过top/ps命令却看不出来用户态应用程序占用太多的内存空间, 那么内核模块可能发生了内存泄露

# top -m 5
​
User 4%, System 2%, IOW 0%, IRQ 0%
User 49 + Nice 0 + Sys 32 + Idle 1120 + IOW 0 + IRQ 0 + SIRQ 1 = 1202
​
 PID USER     PR  NI CPU% S  #THR     VSS     RSS PCY Name
 4264 system   18  -2   2% S    95 1765108K  98260K  fg system_server
 5145 u0_a41   20   0   2% S    41 1692144K  65372K  bg com.douyu.xl.douyutv
 7063 root     20   0   0% R     1   4532K   1548K  fg top
 2602 root     RT   0   0% D     1      0K      0K  fg vdec-core

2、查看Slab 内存

SLAB是Linux内核中按照对象大小进行分配的内存分配器。

通过SLAB的信息来查看内核模块占用的内存空间:

方法1. 查看meminfo文件

# cat /proc/meminfo | grep Slab
​
 Slab:      121588 kB
​
 ++++++++++++++++++++++++++++++++++++++++++++++++++++++

方法2. 查看slabinfo文件

# cat /proc/slabinfo 
 slabinfo - version: 2.1
 # name       <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs>    <sharedavail>
​
 cifs_small_rq     31   32   448   8   1 : tunables  54  27   8 : slabdata    4    4    0
​
 cifs_request      5    5  16512   1   8 : tunables   8   4   0 : slabdata    5    5    0
​
 cifs_oplock_structs    0    0   64  59   1 : tunables  120  60   8 : slabdata    0    0    0
​
 ......
​
 size-32       29904  29904   32  112   1 : tunables  120  60   8 : slabdata   267   267    0
​
 kmem_cache      156   156  2688   1   1 : tunables  24  12   8 : slabdata   156   156    0

一般查看slabinfo文件就足以,如果发现slabinfo中占用内存过大,那基本可以断定,内核模块出现了内存泄露了
还有个命令 slabinfo 也是可以看,其实也是去读 /proc/slabinfo 后可视化出来

3.Kmemleak工具

kmemleak的简单使用

Linux内核的Kmemleak实现内存泄露检测

Demo:

看看下面这个函数是哪里导致的内存泄漏呢?

char *wr_pr_debug_begin(u8 const *data, u32 len, char *string)
 {
 int ii;
 string = kmalloc(len * 2 + 1, GFP_KERNEL);
 for (ii = 0; ii < len; ii++)
 sprintf(&string[ii * 2], "%02X", data[ii]);
 string[len * 2] = 0;
 return string;
 }
 char *wr_pr_debug_end(char *string)
 {
 kfree(string);
 return "";
 }
 void test()
 {
 char *read = 0;
 pr_debug("%s RD%02X%02X%02X -> %s%s\n", st->hw->name,
 i2c_addr, reg, length,
 wr_pr_debug_begin(data, length, read),
 wr_pr_debug_end(read));
 }

一眼可能不容易看出上面的有什么问题,有kmalloc,有kfree 成对出现的。

问题正好出在 pr_debug 这个函数中的参数传递, 熟悉函数调用传参的人应该会知道编译器一般对参数的处理采用堆栈的方式,是一个先进后出的过程,这样参数的执行一般是逆序的(由于编译器实现的不同,这个过程不是确定的),这样kfree会在kmalloc之前运行,导致每次运行都会泄漏一点内存。

参考资料

Resolving Memory Leaks In Linux Kernel

Slab Allocator

Proc Info

Using Crash Debugger

上一篇下一篇

猜你喜欢

热点阅读