记录一次kernel内存泄漏的查找定位过程

来源:互联网 发布:vb中picturebox的属性 编辑:程序博客网 时间:2024/06/05 09:43

Bug描述:压力测试一个小工程时发现内存逐渐减少,10个小时后出现OOM

Bug定位过程:

  • 对整个工程模块进行分解,逐步缩小范围,由于整个工程包括几个相对独立的小模块,而整个工程采用单进程多线程的模型,导致进行分解时,要特别注意相互之间的耦合,只能逐步分离各个模块,运行测试(这里如果采用多进程模型,定位会更快一些,一个完整的功能,放在一个进程和多进程中,多进程天然的将功能细化了,定位问题,范围更小)
  • 在经过一段折磨人的拆分过程后,最后把问题定位到整个工程中一个小模块功能内。在对该模块进行了反复的代码review后,没有发现什么异常,甚至没有内存申请的操作。
  • 代码层面没有找到突破的情况下,重新通过各种命令查看了内存状态,由于在此之前一直通过free命令查看内存,发现长时间后free命令输出的可用内存在逐渐减少,但忽略了一点:通过top命令单独查看模块进程占用的内存时,该进程的rss段一直保持稳定,没有大幅度增长。
  • 基于前一步的发现,怀疑是kernel的内存有泄漏,查看/proc/meminfo发现一个疑点:slab内存占用很高,且SUnreclaim的slab一直在增加,此时基本确定kernel内存泄漏。
  • 通过kmemleak对内核内存进行了分析,定位在到一个函数接口中:
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啊,好像成对出现的。
考验基本功的时候到了,熟悉函数调用传参的人应该会知道编译器一般对参数的处理采用堆栈的方式,是一个先进后出的过程,这样参数的执行一般是逆序的(由于编译器实现的不同,这个过程不是确定的),这样kfree会在kmalloc之前运行,导致每次运行都会泄漏一点内存。上面是一个debug输出,暂时注释掉后压测,问题解决,内存保持稳定。

总结:整个定位过程其实比较简单,如果第一步看下/proc/meminfo可能会更快的定位问题(由于这个kernel driver是“大厂”提供,以为不会出问题,一直从上层的角度去找问题,所以没有太关注kernel相关内存的使用),导致内存泄漏的原因也很简单,出现这种问题的原因,首先编写者的基本功一般,更主要的原因是编写者出于“炫技”的方式去写了这段代码,如果老老实实封装一个debug函数,按照正常顺序调用也就没有问题了,而且这种每次打印进行kmalloc的方式,对性能也是有些影响的。总之基本功还是很重要,而且不要驾驭自己驾驭不了的编码方式。

原创粉丝点击