分区页框分配器

from:分区页框分配器


内核有一个子系统,称之为分区页框分配器(zoned page frame allocator),这个子系统处理对连续页框组的内存分配请求,其主要组成如下。
numa

内存管理区分配器示意图

其中,管理区分配器接受动态内存分配与释放的请求,再请求分配的情况下,该部分搜索一个能满足所有请求的一组连续页框内存的管理区。在每个管理区内,页框被名为『伙伴系统』的部分来处理,为大刀更好的系统性能,一小部分页框保留在高速缓存中用于快速地满足对单个页框分配的请求。

请求和释放页框的几个重要函数如下,如果分配成功,则返回一个分配页的线性地址,如果分配失败,则返回NULL。

分配页框


分配页框一般使用alloc_pages,如果分配失败则返回NULL,可以通过参数gfp_mask指定寻找的方法。


函数名说明
alloc_pages申请一个连续的页框,返回第一个所分配的页框描述符的地址
alloc_page用于获得一个页框的宏
__get__free_pages类似于alloc_pages,但返回第一个所分配页的线性地址
__get_free_page用于获得一个单独的页框的宏
get_zeroed_page用来获取填满0页框的宏,返回所获取页框的线性地址
__get_dma_pages用这个宏获得适用于DMA的页框

alloc_pages函数的完整带参数是alloc_pages(gfp_mask, order),其中order是次方,用于请求2^order个连续的页框。gfp_mask是一组标志,它指明了如何寻找空闲的页框,gfp_mask标志如下。

标志名说明
__GFP_DMA所请求的页框必须处于ZONE_DMA管理区
__GFP_HIGHMEM所请求的页框必须处于ZONE_HIGHMEM管理区
__GFP_WAIT允许内核对等待空闲页框的当前进程进行阻塞
__GFP_HIGH允许内核访问保留的页框池
__GFP_IO允许内核再地段内存页上执行I/O传输以释放页框
__GFP_FS如果为0,则不允许内核执行依赖于文件系统的操作
__GFP_COLD所请求的页框可能为冷页
__GFP_NOWARN一次内存分配失败将不产生警告信息
__GFP_REPEAT内核重试内存分配直到成功
__GFP_NOFAIL与__GFP_REPEAT相同
__GFP_NORETRY一次内存分配失败后不再重试
__GFP_NO_GROWslab分配器不允许增大slab高速缓存
__GFP_COMP属于扩展页的页框
__GFP_ZERO返回任何的页框必须被填满0

实际上,Linux大多数都是用的组合值,而不是单独的某一个值。所以gfp_mask参数如下:


标志名说明
GFP_ATOMIC__GFP_HIGH
GFP_NOIO__GFP_WAIT
GFP_NOFS__GFP_WAIT | __GFP_IO
GFP_KERNEL__GFP_WAIT | __GFP_IO | __GFP_FS
GFP_USER__GFP_WAIT | __GFP_IO | __GFP_FS
GFP_HIGHUSER__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HIGHMEM

释放页框


下面几个函数中的任何一个宏都可以释放页框,但是有细微的差别:

函数名说明
__free_pages该函数首先检查page指向的页描述符(page),如果该页框未被保留,就把描述符的count字段减1,如果count变为0,就假定从page对应的页框开始的一段连续的页框不再被使用。在这种情况下,该函数释放页框。
free_pages释放页框
__free_page释放单个页框
free_page释放单个页框