1、a、物理内存分配的page allocator 是页面级的内存分配,是建立在页面伙伴关系的基础上的分配方式。
只能分配2 order次方大小的物理页面。
mem_map、物理内存、虚拟地址空间的关系如下图:
TODO
b、内存分配的两个基本函数
alloc_pages
__get_free_pages
两者都调用了alloc_pages_node来分配物理页面。
2、gfp_mask
gfp_mask是用于控制内存分配行为的掩码。
a、主要的掩码
__GFP_DMA : 在ZONE_DMA标识的内存区域中查找空闲页。
__GFP_HIGHMEM :在ZONE_HIGHMEM标识的内存区域查找空闲页。
__GFP_WAIT : 当前正在向内核申请页分配的进程可以阻塞,调度器可以调度另一个进程。
b、几个常用掩码
GFP_ATOMIC : 不带__GFP_WAIT标识,不可被阻塞,用于原子操作,适用于中断上下文和非进程上下文。
GFP_KERNEL : 常用的页分配标识,可阻塞。
c、内存页面分配的物理位置
__GFP_HIGHMEM:先在ZONE_HIGHMEM中查找空闲页,再到ZONE_NORMAL中查找,然后在ZONE_DAM查找,没有空闲页就失败。
没有指明__GFP_HIGHMEM或者__GFP_DMA,则默认相当于__GFP_NORMAL,优先在ZONE_NORMAL中查找空闲页,其次是ZONE_DMA。
__GPF_DMA:只能在ZONE_DMA中查找空闲页面。
3、alloc_pages + page_adress 或 kmap
alloc_pages(ffp_mask , order)
分配连续的物理页面
返回的是struct page *类型的页面指针
a、如果alloc_pages的gfp_mask中没有用到GFP_HIGHMEM,分配的物理页面来自ZONE_NORMAL或者ZONE_DMA。
page_address可以用来获得分配页面的线性地址
b、如果alloc_pages的gfp_mask中用到了GFP_HIGHMEM,分配的物理页面来自ZONE_HIGHMEM、ZONE_NORMAL或者ZONE_DMA。
kmap : void *kmap(struct page *page) : 可能引起睡眠。
kunmap :void kunmap(struct page * page)
kmap_atomic : 原子的,不引起睡眠。
alloc_page(gfp_mask) : 分配一个物理页面。
4、__get_free_pages
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
分配2 order次幂的连续物理页面。
返回值是内核的线性地址。
内部调用了alloc_pages page_address。
不能从高端内存中分配物理页面。
__get_free_page(gfp_mask) : 分配单个页面。
5、get_zeroed_page
分配一个物理页,同时将页面内容填充0,返回内核线性地址。
6、get_dma_pages
用于从ZONE_DMA中分配物理页,返回线性地址。
7、内存的释放
alloc_pages __free_pages
__get_free_pages free_pages