Linux 内核学习笔记系列,内存管理部分,内存管理的一些补充说明。

分配函数的选择

如果需要连续的物理页,可以使用某个低级页分配器(分区页框分配器里请求页框和释放页框的函数/宏)或 kmalloc() 函数。

对于中断处理程序和其他不能睡眠的代码段,使用 GFP_ATOMIC 表示不进行睡眠的高优先级分配。

对于可以睡眠的代码,使用 GFP_KERNEL 表示如果有必要可以进行睡眠。

如果想从高端内存进行分配,可以使用 alloc_pages() 函数。 该函数返回一个指向 struct page 结构的指针,而不是一个指向某个逻辑地址的指针。因为高端内存很可能没有被映射,要获得真正的指针,需要调用 kmap() 函数把高端内存映射到内核的逻辑地址空间。

如果不需要物理上连续的页,而仅仅需要虚拟地址上连续的页,可以使用 vmalloc() 函数(但该函数相对 kmalloc() 有一定的性能损失)。

如果要创建和撤销很多大的数据结构,可以考虑建立 slab 高速缓存。

vmalloc()kmalloc()

vmalloc() 为了把物理上不连续的页转换为虚拟地址空间上连续的页,必须专门建立页表项,而且因为它们物理上是不连续的,所以必须一个一个进行映射,这会导致比直接内存映射大得多的 TLB 抖动。

尽管在某些情况下才需要物理上的连续内存块,但出于性能的考虑,很多内核代码都使用 kmalloc()。除非在不得已时才使用 vmalloc(),比如动态装载模块时,需要获得大块内存。

slub 分配器

slub 分配器逐渐取代了 slab 分配器,成为默认的内存分配器。

slub 分配器在 2.6.22 版本引入,它具有设计简单、代码精简、额外内存占用率小、扩展性高,性能优秀、方便调试等很多优点。

内存管理相关函数调用关系

分配连续内存的函数调用关系大致如下:

分配连续内存的函数调用关系

释放连续内存的函数调用关系大致如下:

释放连续内存的函数调用关系