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

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/voidreturn/article/details/72357242 Bug描述...
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/voidreturn/article/details/72357242

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的方式,对性能也是有些影响的。总之基本功还是很重要,而且不要驾驭自己驾驭不了的编码方式。

目录
相关文章
|
8月前
|
Arthas 运维 监控
定位频繁创建对象导致内存溢出风险的思路
定位频繁创建对象导致内存溢出风险的思路
181 1
|
4月前
|
缓存 架构师 算法
Java内存溢出如何解决,Java oom排查方法,10个定位解决办法
在Java开发过程中,有效的内存管理是保证应用程序稳定性和性能的关键。不正确的内存使用可能导致内存泄露甚至是致命的OutOfMemoryError(OOM)。
|
6月前
|
存储 缓存 Linux
linux下定位多线程内存越界问题实践总结
linux下定位多线程内存越界问题实践总结
|
7月前
|
缓存 Shell C语言
用 TDengine 3.0 碰到“内存泄露”?定位问题原因很关键
在本篇文章中,我们将从 GitHub 上的一个关于内存泄漏的 issue入手,和大家探讨下导致内存泄漏的原因,以及如何避免和定位内存泄漏。
105 0
|
8月前
|
SQL Java 关系型数据库
定位频繁创建对象导致内存溢出风险之JDBC MySQL
定位频繁创建对象导致内存溢出风险之JDBC MySQL
182 0
|
9月前
|
存储 算法 安全
【jvm系列-06】深入理解对象的实例化、内存布局和访问定位
【jvm系列-06】深入理解对象的实例化、内存布局和访问定位
187 0
【jvm系列-06】深入理解对象的实例化、内存布局和访问定位
|
10月前
|
存储 缓存 Linux
十八、Linux性能优化实战学习笔记- 内存泄漏了,我该如何定位和处理?
当进程通过 malloc() 申请虚拟内存后,系统并不会立即为其分配物理内存,而是在首次访问时,才通过缺页异常陷入内核中分配内存.对应用程序来说,动态内存的分配和回收,是既核心又复杂的一个逻辑功能模块。管理内存的过程中,也很容易发生各种各样的“事故”.
83 0
|
安全 C语言 C++
【C++要笑着学】C++动态内存管理 | new/delete底层探索 | new/delete实现原理 | 定位new(二)
是这样的,C语言里的 "动态内存管理" 放到 C++ 里面,用起来不是那么爽,所以C++就对这一块进行了升级,本章我们就探索探索 C++的内存管理,顺便复习一下C语言里讲过的动态内存管理的知识。学完本章,单身的同学不用怕了,以后没有对象我们可以 new 一个
144 0
【C++要笑着学】C++动态内存管理 | new/delete底层探索 | new/delete实现原理 | 定位new(二)
|
存储 安全 编译器
【C++要笑着学】C++动态内存管理 | new/delete底层探索 | new/delete实现原理 | 定位new(一)
是这样的,C语言里的 "动态内存管理" 放到 C++ 里面,用起来不是那么爽,所以C++就对这一块进行了升级,本章我们就探索探索 C++的内存管理,顺便复习一下C语言里讲过的动态内存管理的知识。学完本章,单身的同学不用怕了,以后没有对象我们可以 new 一个
135 0
【C++要笑着学】C++动态内存管理 | new/delete底层探索 | new/delete实现原理 | 定位new(一)
|
存储 算法 Java
10-对象的实例化内存布局与访问定位
10-对象的实例化内存布局与访问定位
76 0
10-对象的实例化内存布局与访问定位