简介
分区页框分配器处理对连续页框组的内存分配请求,主要组成如下图所示:
管理区分配器接受动态内存分配与释放的请求,它首先从每CPU页框高速缓存中请求页框,若无法满足才从伙伴系统中请求分配。
源码分析(Linux2.6/mm/page_alloc.c)
buffered_rmqueue()
此函数从指定内存管理区中分配页框,对应上图中的分配机制。
static struct page *buffered_rmqueue(struct zone *zone, int order, int gfp_flags) { unsigned long flags; struct page *page = NULL; int cold = !(gfp_flags & __GFP_COLD); /** * 如果order!=0,则每CPU页框高速缓存就不能被使用,因为每CPU页框高速缓存是对单个页框的管理 */ if (order == 0) { struct per_cpu_pages *pcp; /** * 检查由__GFP_COLD标志所标识的内存管理区本地CPU高速缓存是否需要被补充。 * 其count字段小于或者等于low */ pcp = &zone->pageset[get_cpu()].pcp[cold]; local_irq_save(flags); /** * 当前缓存中的页框数低于low,需要从伙伴系统中补充页框。 * 调用rmqueue_bulk函数从伙伴系统中分配batch个单一页框 * rmqueue_bulk反复调用__rmqueue,直到缓存的页框达到low。 */ if (pcp->count <= pcp->low) pcp->count += rmqueue_bulk(zone, 0, pcp->batch, &pcp->list); /** * 如果count为正,函数从高速缓存链表中获得一个页框。 * count减1 */ if (pcp->count) { page = list_entry(pcp->list.next, struct page, lru); list_del(&page->lru); pcp->count--; } local_irq_restore(flags); /** * 没有和get_cpu配对使用呢? * 这就是内核,外层一定调用了get_cpu。这种代码看起来头疼。 */ put_cpu(); } /** * 内存请求没有得到满足,或者是因为请求跨越了几个连续页框,或者是因为被选中的页框高速缓存为空。 * 调用__rmqueue函数(因为已经保护了,直接调用__rmqueue即可)从伙伴系统中分配所请求的页框(见伙伴系统一文) */ if (page == NULL) { spin_lock_irqsave(&zone->lock, flags); page = __rmqueue(zone, order); spin_unlock_irqrestore(&zone->lock, flags); } /** * 如果内存请求得到满足,函数就初始化(第一个)页框的页描述符 */ if (page != NULL) { BUG_ON(bad_range(zone, page));