page类 page对象指向


内核中alloc_pages系列页框分配函数都是基于伙伴算法实现的,这些函数最终都会调用伙伴算法的入口函数buffered_rmqueue() 。
Linux内核管理物理内存有三种方式,其一就是经典的伙伴算法 。但是伙伴算法分配物理内存的基本单位是页框,因此内核又引入了slab机制,基于此机制实现的物理内存分配器可以快速有效的分配小于页框的物理内存,并且可以有效避免内部碎片 。另外,内核常常会申请单个页框大小的物理内存,因此内核又引入了per-CPU机制,该机制专门用于快速分配单个页框 。
1.__rmqueue()其实buffered_rmqueue()函数仍然没有进行真正的页框分配,该函数首先判断分配阶是否为0,如果是则启用per-CPU机制来分配物理内存,否则调用__rmqueue() 。
static struct page *__rmqueue(struct zone *zone, unsigned int order,int migratetype){struct page *page;retry_reserve:page = __rmqueue_smallest(zone, order, migratetype);if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {page = __rmqueue_fallback(zone, order, migratetype);if (!page) {migratetype = MIGRATE_RESERVE;goto retry_reserve;}}trace_mm_page_alloc_zone_locked(page, order, migratetype);return page;}传递到此函数中的zone表示伙伴算法将从该内存管理区中分配页框,order即分配阶,migratetype表示迁移类型 。该函数首选__rmqueue_smallest()进行内存分配,如果在指定的迁移类型上分配失败后,再选用其他备用的迁移列表进行内存分配,该过程通过__rmqueue_fallback()完成 。总之内核总是在竭尽全力保证满足分配内存的请求 。


更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.

page类 page对象指向

文章插图

page类 page对象指向

文章插图
【page类 page对象指向】


2.__rmqueue_smallest()该函数的实现比较简单,从当前指定的分配阶到最高分配阶依次进行遍历 。在每次遍历的分配阶链表中,根据参数migratetype选择正确的迁移队列 。根据以上的限定条件,当选定一个页框块链表后,只要该链表不为空,就说明可以分配该分配阶对应的页框块 。
一旦选定在当前遍历的分配阶链表上分配页框,那么就通过list_entry()将该页框块从链表上移除 。然后将页框块首页框的PG_buddy标志删除,删除该标志说明当前页框块已经不属于伙伴链表 。并且将该首页框描述符中的priveate置0,该字段中本来保存的是其所处页框块的分配阶 。以上这个过程通过rmv_page_order()完成 。此外,还要更新页框块链表nr_free的值 。
static inlinestruct page *__rmqueue_smallest(struct zone *zone, unsigned int order,int migratetype){unsigned int current_order;struct free_area * area;struct page *page;for (current_order = order; current_order < MAX_ORDER; ++current_order) {area = &(zone->free_area[current_order]);if (list_empty(&area->free_list[migratetype]))continue;page = list_entry(area->free_list[migratetype].next, struct page, lru);list_del(&page->lru);rmv_page_order(page);area->nr_free--;expand(zone, page, order, current_order, area, migratetype);return page;}return NULL;}static inline void rmv_page_order(struct page *page){__ClearPageBuddy(page);set_page_private(page, 0);}__rmqueue_smallest()内部还有一个重要的函数expand() 。进入该函数的条件是当所申请的分配阶order小于当前选中的分配阶current_order,也就是说指定的分配阶链表中没有空闲的页框块,只能选用较大的页框块 。因此,expand()必须按照伙伴算法的分裂原理将比较大的页框块分割成较小的块 。
3.expand()分裂函数的实现也是显而易见的,它完全遵照伙伴算法的分裂原理 。这里有两个分配阶,一个是申请页框时指定的low,一个是在上级函数中遍历时所选定的high 。该函数从high分配阶开始递减向low遍历,也就是从较大的页框块开始依次分裂 。


特别声明:本站内容均来自网友提供或互联网,仅供参考,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。