本文目的在于分析Linux内核中的vmalloc函数。内核版本为2.6.31。
我们知道物理上连续的映射对内核是最好的,但不是总能成功。在分配一大块内存时,可能无法找到连续的内存块。在用户空间这不是问题,因为普通进程设计为使用处理器的分页机制,当然这会降低速度并占用TLB。
在内核中也可以使用同样的技术,典型的例子为vmalloc()。
vmalloc是一个接口函数,内核代码用它来分配在虚拟内存中连续但在物理内存中不一定连续的内存。
void *vmalloc(unsigned longsize);
该函数只需要一个参数,用于指定所需内存的长度,单位为字节。但是要注意,vmalloc是以页大小为单位分配内存的。
使用vmalloc最著名的实例的内核对模块的实现,因为模块可能在任何时候加载,如果模块数据较多,那么无法保证有足够的连续内存可用。如果可以用小块内存拼接出足够的内存,使用vmalloc便可以规避该问题。
因为用于vmalloc的内存页总是映射在内核地址空间中,因此使用ZONE_HIGHMEM内存域的页要优于其他内存域。如果内核没有高端内存域,则实际上是使用的NORMAL内存域,只是使用了页表。
内核在管理虚拟内存中的vmalloc区域时,由于内存是分散的,必须跟踪哪些子区域被使用、哪些是空闲的。为此定义了一个数据结构struct vm_struct,将所有使用的部分保存在一个链表中。
vmalloc()直接调用了__vmalloc_node()函数: