linux内核内存泄露检测

linux内核内存泄露检测,第1张

经常碰到系统跑着跑着一段时间内存满了,出现内存泄漏的问题,系统软件太庞大,这类问题又不好直接从源码中分析,所以需要借助工具来分析了,kmemleak就是这样的一个工具。

在Kernel hacking中打开CONFIG_DEBUG_KMEMLEAK =y即使能了kmemleak,其实就是开了一个内核线程,该内核线程每10分钟(默认值)扫描内存,并打印发现新的未引用的对象的数量。kmemleak的原理其实就是通过kmalloc、vmalloc、kmem_cache_alloc等内存的分配,跟踪其指针,连同其他的分配大小和堆栈跟踪信息,存储在PRIO搜索树。如果存在相应的释放函数调用跟踪和指针,就会从kmemleak数据结构中移除。下面我们看看具体的用法。

查看内核打印信息详细过程如下:

1、挂载debugfs文件系统

   mount -t debugfs nodev /sys/kernel/debug/

2、开启内核自动检测线程

   echo scan > /sys/kernel/debug/kmemleak

3、查看打印信息

   cat /sys/kernel/debug/kmemleak

4、清除内核检测报告,新的内存泄露报告将重新写入/sys/kernel/debug/kmemleak

   echo clear > /sys/kernel/debug/kmemleak

内存扫描参数可以进行修改通过向/sys/kernel/debug/kmemleak 文件写入。 参数使用如下:

  off 禁用kmemleak(不可逆)

  stack=on 启用任务堆栈扫描(default)

  stack=off 禁用任务堆栈扫描

  scan=on 启动自动记忆扫描线程(default)

  scan=off 停止自动记忆扫描线程

  scan=<secs>设置n秒内自动记忆扫描,默认600s

  scan 开启内核扫描

  clear 清除内存泄露报告

  dump=<addr>转存信息对象在<addr>

通过“kmemleak = off”,也可以在启动时禁用Kmemleak在内核命令行。在初始化kmemleak之前,内存的分配或释放这些动作被存储在一个前期日志缓冲区。这个缓冲区的大小通过配CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE设置。

1. 在需要内存泄漏检查的代码的开始调用void mtrace(void) (在mcheck.h中? 有声明). mtrace为malloc等函数安装hook, 用于记录内存分配信息.在需要内存泄漏检查的代码的结束调用void muntrace(void).\x0d\x0a注意: 一般情况下不要调用muntrace, 而让程序自然结束. 因为可能有些释放内存代码要到muntrace之后才运行.\x0d\x0a\x0d\x0a2. 用debug模式编译被检查代码(-g或-ggdb)\x0d\x0a\x0d\x0a3. 设置环境变量MALLOC_TRACE为一文件名, 这一文件将存有内存分配信息.\x0d\x0a\x0d\x0a4. 运行被检查程序, 直至结束或muntrace被调用.\x0d\x0a\x0d\x0a5. 用mtrace命令解析内存分配Log文件($MALLOC_TRACE)\x0d\x0a(mtrace foo $MALLOC_TRACE, where foo is the executible name)\x0d\x0a如果有内存泄漏, mtrace会输出分配泄漏\x0d\x0a内存的代码位置,以及分配数量.\x0d\x0a\x0d\x0a附加说明\x0d\x0a1. 可以将mtrace, muntrace放入信号处理函数(USR1, USR2), 以动态地进行内存泄漏检查控制.\x0d\x0a2. mtrace是个perl代码, 如果你对符号地址与代码文本的转换感兴趣, 可以读一下.\x0d\x0a3. again, 尽量不要用muntrace()\x0d\x0aFor C++ Leak:\x0d\x0a检查内存泄漏的方法除glibc提供外;还可以试试一些专用的程序。\x0d\x0a很奇怪,redhat 9 居然不带mtrace perl脚本,只好下载gcc源码编译了\x0d\x0awget --passive-ftp ftp://rpmfind.net/linux/redhat/9 ... -2.3.2-11.9.src.rpm\x0d\x0arpm -ivh glibc*.src.rpm\x0d\x0acd /usr/src/redhat/SPECS/\x0d\x0arpmbuild -ba glibc-9.spec\x0d\x0acd /var/tmp/glibc-2.3.2-root/usr/bin/\x0d\x0acp mtrace /usr/bin/\x0d\x0a调试方法如下:\x0d\x0avi a.c\x0d\x0a1 #include\x0d\x0a2\x0d\x0a3 int main()\x0d\x0a4 {\x0d\x0a5 mtrace()\x0d\x0a6 malloc(10)\x0d\x0a7 malloc(16)\x0d\x0a8 return 0\x0d\x0a9 }\x0d\x0a$gcc -g a.c #记得编译带-g调试选项\x0d\x0a$export MALLOC_TRACE=a.log\x0d\x0a$./a.out\x0d\x0a$unset MALLOC_TRACE #记得执行完后unset变量,否则可能运行其他命令可能覆盖log\x0d\x0a$mtrace a.out a.log\x0d\x0aMemory not freed:\x0d\x0a-----------------\x0d\x0aAddress Size Caller\x0d\x0a0x09b08378 0xa at /XXX/a.c:6\x0d\x0a0x09b08388 0x10 at /XXX/a.c:7\x0d\x0a可以看到,会显示未释放动态空间的代码具体位置。

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

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

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

方法1. 查看meminfo文件

方法2. 查看slabinfo文件

一般查看slabinfo文件就足以,如果发现slabinfo中占用内存过大,那基本可以断定,内核模块出现了内存泄露了

还有个命令 slabinfo 也是可以看,其实也是去读 /proc/slabinfo 后可视化出来

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

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

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

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

Resolving Memory Leaks In Linux Kernel

Slab Allocator

Proc Info

Using Crash Debugger


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/7605195.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-07
下一篇2023-04-07

发表评论

登录后才能评论

评论列表(0条)

    保存