如何确定Linux内核模块是否存在内存泄漏问题

10

为了测试内核泄漏内存时的行为,我正在编写一个内核模块,不断地分配内存,例如代码看起来像这样:

int bytesLeaked = 128000;
char *var = kmalloc(bytesLeaked, GFP_KERNEL); 
if (var != NULL)
printk("leaked %d bytes at address %x\n", bytesLeaked, (unsigned int)var);

这段代码在init_module中。我有以下问题:
  1. 如何确定代码是否泄露内存?lsmod并没有显示太多信息。
  2. 互联网上的教程只展示了在init_module和exit_module中的代码。如果我想在模块插入后但在退出之前的一段时间内进行内存分配怎么办?
  3. 我能否编写仅在用户发出指令时才会泄漏内存的代码,例如,用户空间程序可以调用系统调用,导致模块泄漏内存吗?
2个回答

20

如果你需要检查一个内核模块是否泄露了内存,且你的机器采用x86架构,那么你可以使用KEDR系统来进行内存泄漏检测。

KEDR不需要重新构建内核。在线文档(例如“开始”)描述了如何安装和使用KEDR。简而言之,步骤如下:

安装(来自源代码):解压缩源代码文件- cmake <...> - make - make install

在加载模块之前启动KEDR:

$ kedr start <name_of_the_module_to_analyze> -f leak_check.conf

然后,您可以像往常一样加载模块并与之交互。在卸载时,KEDR会在debugfs中生成一个报告(通常将debugfs挂载到/sys/kernel/debug),例如:

$ cat /sys/kernel/debug/kedr_leak_check/info
Target module: "...", 
Memory allocations: 3
Possible leaks: 2
Unallocated frees: 0

来自 /sys/kernel/debug/kedr_leak_check/ 的文件possible_leaks提供了每个泄漏的内存块的信息(地址、大小和调用堆栈)。

最后,您可以停止KEDR(请注意/sys/kernel/debug/kedr_leak_check/将消失):

kedr stop

如果你使用的是非x86架构的系统,Kmemleak可能也会有所帮助,尽管它更难使用。你可能需要重新构建内核,并将CONFIG_DEBUG_KMEMLEAK参数设置为“y”。不过,Kmemleak也是一个非常有用的工具。有关详细信息,请参见内核源代码中的Documentation/kmemleak.txt


2
KEDR支持2.6.31或更新的内核版本。我的内核版本是2.6.28。看起来KEDR不能使用。我将尝试寻找适用于我所拥有的内核的类似工具。 - kakinada

0
  1. 当代码分配一块内存(例如使用 kmalloc())并且在没有释放该内存块的情况下失去了所有对该内存块的引用时,代码会泄漏内存。您的代码没有这样做,因为您仍然在作用域中并指向您的内存块。如果您在下一行添加 var = NULL;,那么您就有了一个真正的内存泄漏。

  2. 绝对可以让用户空间中的事件触发您的内核模块开始分配内存。我不确定是否可以直接通过系统调用来实现,但如果不能,则有许多其他方法可以完成任务。您只需要选择一个并实施它。即使是像每次想要触发内存分配时都 touch 一个预定文件这样简单的事情也应该可以工作。虽然我不明白为什么您不能让您的 init_module 代码生成一个线程,该线程随时间定期分配内存,如果这是您想要的行为。


4
一个内存泄漏的定义特征是分配的内存没有被释放,而不一定是没有对它的引用。此外,假设var在某个时间点超出了其范围,在这个时候你的引用计数会归零。 (让我们忽略在C语言中“引用”这个词并没有很好地定义的事实。) - Karmastan
谢谢。我尝试编写线程生成的代码,但代码相当复杂 http://www.scs.ch/~frey/linux/kernelthreads.html。您能否提供有关如何通过用户空间事件触发内存分配而无需系统调用的见解? - kakinada
KEDR支持2.6.31或更新的内核版本。我的内核版本是2.6.28。看起来KEDR不能使用。我将尝试寻找适用于我所拥有的内核的类似工具。 - kakinada

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接