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

how to determine if a Linux kernel module is leaking memory

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

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

此代码在 init_module 中。我有以下问题

  • 如何判断代码是否有内存泄露? lsmod 没有透露太多。
  • 网上的教程只展示了init_module和exit_module中的代码。如果我希望在插入模块之后但退出之前的一段时间内进行内存分配怎么办?
  • 我是否可以编写仅在用户发出指令时才泄漏内存的代码,例如用户空间程序可以进行系统调用导致模块泄漏内存吗?

  • 如果您需要检查内核模块是否有内存泄漏,并且您的机器具有 x86 架构,您可以使用 KEDR 系统,它包含一个内存泄漏检测器。

    KEDR 不需要您重建内核。在线文档(例如,参见"入门")描述了如何安装和使用 KEDR。简而言之,程序如下。

    安装(从源代码):解压缩源存档 - cmake <...> - make - make install

    在加载模块之前启动 KEDR:

    1
    $ kedr start <name_of_the_module_to_analyze> -f leak_check.conf

    然后你可以加载你的模块并像往常一样使用它。卸载后,KEDR会在debugfs中给你一个报告(通常debugfs挂载到/sys/kernel/debug),例如:

    1
    2
    3
    4
    5
    $ 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/会消失):

    1
    kedr stop

    如果您使用的是 x86 以外的体系结构,Kmemleak 也可能会有所帮助,尽管它使用起来有点困难。您可能需要将 CONFIG_DEBUG_KMEMLEAK 参数设置为"y"来重建内核。尽管如此,Kmemleak 也是一个非常有用的工具。有关详细信息,请参阅内核源代码中的 Documentation/kmemleak.txt。


  • 代码在分配内存块(例如使用 kmalloc())时会泄漏内存,然后丢失对该内存块的所有引用而没有先释放它。您的代码没有这样做,因为您仍然有 var 在范围内并指向您的内存块。如果你在下一行添加 var = NULL;,那么你有一个真正的内存泄漏。

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