【开发工具】【kmemleak】内存泄漏检测工具(kmemleak)的使用

获取更多相关的嵌入式开发工具,可收藏系列博文,持续更新中:
【开发工具】嵌入式常用开发工具汇总帖


kmemleak原理

kmemleak(kernel memory leak detector)是检测内核空间的内存泄漏的调试工具。检测对象是memblock_alloc、kmalloc、vmalloc、kmem_cache_alloc等函数分配的内存块,该内存块由struct kmemleak_object来描述(简称为object)。kmemleak的实现原理非常简单,通过暴力扫描内存(假定内存中存放的都是指针,以ARM64为例,每次扫描8个字节),如果找不到指向起始地址或者内存块任何位置的指针,则分配的内存块被认为是孤立的。这意味着内核可能无法将分配内存块的地址传递给释放函数,因此该内存块被视为内存泄漏。

kmemleak配置

kmemleak(kernel memory leak detector)是检测内核空间的内存泄漏的调试工具。可以在make menuconfig编译配置内核时,添加kmemleak功能配置。

内容
CONFIG_DEBUG_KMEMLEAK=y在kernel hacking中打开CONFIG_DEBUG_KMEMLEAK宏,表示内核支持kmemleak功能。
CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN=y如果开启CONFIG_DEBUG_KMEMLEAK_AUTO_SCAN宏,则会触发自动扫描,调用start_scan_thread函数进行扫描。
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=n如果定义了CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏或者通过cmdline设置为kmemleak=off,则默认关闭kmemleak。如果cmdline中设置kmemleak=on,则表示默认开启kmemleak功能。如果没有定义CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF宏,则默认是开启kmemleak功能。
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=20000

在启动阶段,由于默认 CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE 配置过小,系统启动阶段 early log 溢出,会导致 kmemleak 被自动禁用.

因此需要将值设置的大一些

kmemleak使用

使用kmemleak可以很方便地检测出内核态的内存泄露。可以用于设备驱动程序或内核模块的评估。虽然kmemleak的扫描算法存在漏报和误报的可能,但是并不影响我们的使用。因为这个工具的目的是为了给我们进一步分析提供线索,并不需要绝对精确,小概率的误报和漏报并不影响这个工具的实用性

挂载debugfs

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

开启kmemleak扫描

echo 【参数】 > /sys/kernel/debug/kmemleak

举例:
echo stack=on > /sys/kernel/debug/kmemleak
echo scan=on > /sys/kernel/debug/kmemleak
echo scan=10 > /sys/kernel/debug/kmemleak
echo scan > /sys/kernel/debug/kmemleak

具体参数说明:

参数内容
off禁用kmemleak。不再跟踪内存分配和释放。一旦禁用,就不能再次开启。
stack=on启用线程栈区域的扫描。默认是on
stack=off禁用线程栈区域的扫描
scan=on开启kmemleak内核线程的自动扫描。默认为on
scan=off停止kmemleak内核线程的自动扫描
scan=<s>设置kmemleak线程执行扫描时间间隔。单位为秒,默认为600s(10分钟)。0s表示停止自动扫描
scan手动触发扫描,立即扫描
clear清除检测出的数据,即清除之前判断为内存泄露的object信息,会把这些object标记为KMEMLEAK_GREY,并不会把object从红黑树和双向链表中删除,不在/sys/kernel/debug/kmemleak中显示,只是不显示,可以使用dump参数进行确定。在使用kmemleak前清除没有关系的信息时使用
dump=<addr>显示addr对应object信息

详细的使用方法参考kenrel文档Documentation/dev-tools/kmemleak.rst

获取kmemleak信息

详细的输出信息通过/sys/kernel/debug/kmemleak获取

cat /sys/kernel/debug/kmemleak

kmemleak实例

编译kmemleak_test

构造一个内存泄漏的实例,具体代码如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/page.h>
 
void kmemleak_memalloc(void)
{
    char *pmem;
   
    pmem = kmalloc(300, GFP_KERNEL);
    if (!pmem)
    {
        printk("[Kmemleak]: kmalloc fail!\n");
    }
    else
    {
        printk("[Kmemleak]: kmalloc return %p \n", pmem);
    }
}
 
int __init kmemleak_test_init(void)
{
   
    printk("[Kmemleak]: kmemleak_test_init! \n");
 
    kmemleak_memalloc();
 
    return 0;
}
 
void __exit kmemleak_test_exit(void)
{
    printk("[Kmemleak]: kmemleak_test_exit now \n");
}
 
 
module_init(kmemleak_test_init)
module_exit(kmemleak_test_exit)
 
MODULE_LICENSE("GPL");

Makefile如下:

Makefile需要注意平台(ARCH)、交叉编译工具链(CROSS_COMPILE)、内核路径(KERDIR)等,根据实际项目配置。

obj-m = kmemleak_test.o

export ARCH=arm
export CROSS_COMPILE=...

KERDIR := ...
CURDIR := $(shell pwd)

all:
	make -C $(KERDIR) M=$(CURDIR) modules
clean:
	make -C $(KERDIR) M=$(CURDIR) clean

执行make名,编译生成kmemleak_test.ko。

加载kmemleak_test

tftp上传kmemleak_test.ko,通过insmod kmemleak_test.ko加载

# tftp -gr kmemleak_test.ko 10.15.140.133
kmemleak_test.ko     100% |*******************************|  3608   0:00:00 ETA
# 
# insmod kmemleak_test.ko 
[  128.494465] [Kmemleak]: kmemleak_test_init! 
[  128.494513] [Kmemleak]: kmalloc return c1f93a00

开启kmemleak扫描后,过一段时间,检测到内存泄漏事件

# echo stack=on > /sys/kernel/debug/kmemleak
# 
# echo scan=on > /sys/kernel/debug/kmemleak
# 
# echo scan=10 > /sys/kernel/debug/kmemleak
[  180.771875] kmemleak: Automatic memory scanning thread ended
[  180.774379] kmemleak: Automatic memory scanning thread started
[  192.744462] kmemleak: 1 new suspected memory leaks (see /sys/kernel/debug/kmemleak)
# 
# cat /sys/kernel/debug/kmemleak
unreferenced object 0xc1f93a00 (size 512):
  comm "insmod", pid 174, jiffies 4294950135 (age 76.610s)
  hex dump (first 32 bytes):
    00 3c f9 c1 00 00 00 00 00 00 00 00 00 00 00 00  .<..............
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace:
    [<c008fb48>] kmem_cache_alloc+0x88/0xf4
    [<bf02b014>] kmemleak_memalloc+0x14/0x44 [kmemleak_test]
    [<bf02d010>] 0xbf02d010
    [<c00096f4>] do_one_initcall+0x100/0x120
    [<c00541cc>] do_init_module+0x54/0x198
    [<c0055880>] load_module+0x150c/0x1abc
    [<c0055fe4>] SyS_finit_module+0x88/0x90
    [<c000de00>] ret_fast_syscall+0x0/0x48
    [<ffffffff>] 0xffffffff
# 

解析kmemleak日志

通过kmemleak report的输出信息,我们可以获取如下信息:

  • 产生泄漏内存块对应的object的起始地址为0xc1f93a00
  • 泄漏的字节大小为512字节
  • 进程名为insmod,pid为174,创建object时的jiffies为4294950135
  • 泄漏内存块的钱32字节数据被打印
  • 泄漏点的backtrace信息被打印

参考:深入理解内存泄漏检查kmemleak - 知乎

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Evan_ZGYF丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值