【问题标题】:Kernel modules __init macro in CC中的内核模块__init宏
【发布时间】:2018-02-01 08:39:25
【问题描述】:

我想为 Linux 创建一个可加载的内核模块。 这是代码

#include <linux/module.h>
#include <linux/init.h>

static int __init mymodule_init(void)
{
 printk ("My module worked!\n");
        return 0;
}

static void __exit mymodule_exit(void)
{
 printk ("Unloading my module.\n");
        return;
}

module_init(mymodule_init);
module_exit(mymodule_exit);

MODULE_LICENSE("GPL");

现在注意__init 宏。正如文档所说:

__init 宏向编译器指示该关联函数 仅在初始化期间使用。编译器放置所有标记的代码 使用 __init 进入一个特殊的内存部分,该部分在之后被释放 初始化

我试图理解为什么初始化方法最终会导致内存泄漏。是不是因为栈中函数调用的先进先出配置?

【问题讨论】:

  • 以上引用中的什么表示内存泄漏?
  • 需要将__init方法放在一个特殊的内存部分
  • "...在初始化后被释放"?对我来说似乎不是泄漏。
  • 是由于堆栈中函数调用的 FIFO 配置 -- 什么?堆栈甚至不是 FIFO 结构。

标签: c linux-kernel macros


【解决方案1】:

概括地说:

可执行代码(源代码编译成什么)占用内存。现代 CPU 会读取指令所在的内存部分并执行它们。对于大多数用户空间应用程序,进程内存的代码段被加载一次,并且在程序执行期间永远不会更改。代码总是存在的,除非程序员玩弄它。

这不是问题,因为操作系统将管理进程的虚拟内存,而冷代码段最终将被卸载到交换文件中。物理内存永远不会像用户空间那样“浪费”。

对于代码在特权模式下运行的内核,不会像在用户模式下那样“卸载”未使用的页面。如果将一个函数放在内核常规代码段中,只要内核运行,它就会占用物理内存,这可能是相当长的时间。如果一个函数只调用一次,那是相当浪费空间的。

现在,虽然可加载内核模块通常可以加载和卸载,因此它们的代码可能不会无限期地占用空间,但为只被调用一次的函数占用空间仍然有些浪费。

由于现代 CPU 将代码视为可执行数据的一种形式,因此可以将该数据放入不会无限期保留的内存段中。该函数被加载,然后被调用,然后该段可以用于其他用途。这就是__init 宏指示编译器执行的操作。发出调用后可以轻松卸载的代码。

【讨论】:

  • 你太棒了,谢谢。由于哪些原因内核内存不可交换? ps:在用户进程中是占用内存的代码还是栈中的函数调用?
  • @Tantaros - 调用堆栈不包含代码,它包含调用的变量和返回的指令指针(除其他外)。该指针是可执行代码中的一个位置。代码与堆栈本身是分开的,完全位于另一个段中。至于内核不受交换的影响,这是最好避免的一大堆并发症。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-08
  • 2023-04-04
  • 2014-03-01
  • 1970-01-01
相关资源
最近更新 更多