内核的部分函数带有__init和__exit宏,负责“初始化”和“清理收尾”该函数。如果该模块被编译进内核,而不是动态加载。宏 __init的使用会在初始化完成后丢弃该函数并收回所占内存,

宏__initdata同__init 类似,只不过对变量有效。简单来说是指示gcc把标记的数据或者函数放到指定sector。

linux中把一些启动及初始化时候用的数据用__init标识,然后在适当的时候把它们释放,回收内存。

宏__exit将忽略“清理收尾”的函数如果该模块被编译进内核。同宏 __exit一样,对动态加载模块是无效的。这很容易理解。编译进内核的模块 是没有清理收尾工作的, 而动态加载的却需要自己完成这些工作。

这些宏在头文件linux/init.h定义,用来释放内核占用的内存。 当你在启动时看到这样的Freeing unused kernel memory: 236k freed内核输出,上面的 那些正是内核所释放的

下面是一些常用的宏:

· __init ,标记内核启动时使用的初始化代码,内核启动完成后不再需要。以此标记的代码位于.init.text 内存区域。它的宏定义是这样的:

·

#define _ _init _ _attribute_ _ ((_ _section_ _ (".text.init")))

· __exit ,标记退出代码,对于非模块无效。

· __initdata ,标记内核启动时使用的初始化数据结构,内核启动完成后不再需要。以此标记的代码位于.init.data 内存区域。

· __devinit ,标记设备初始化使用的代码。

· __devinitdata ,标记初始化设备数据结构的函数。

· __devexit ,标记移除设备时使用的代码。

· xxx_initcall ,一系列的初始化代码,按降序优先级排列。


初始化代码的内存结构



_init_begin -------------------

| .init.text | ---- __init

|-------------------|

| .init.data | ---- __initdata

_setup_start |-------------------|

| .init.setup | ---- __setup_param

__initcall_start |-------------------|

| .initcall1.init | ---- core_initcall

|-------------------|

| .initcall2.init | ---- postcore_initcall

|-------------------|

| .initcall3.init | ---- arch_initcall

|-------------------|

| .initcall4.init | ---- subsys_initcall

|-------------------|

| .initcall5.init | ---- fs_initcall

|-------------------|

| .initcall6.init | ---- device_initcall

|-------------------|

| .initcall7.init | ---- late_initcall

__initcall_end |-------------------|

| |

| ... ... ... |

| |

__init_end -------------------

初始化代码的特点是:在系统启动运行,且一旦运行后马上退出内存,不再占用内存。


一个奔跑的程序员