linux页和页框的区别,Linux页框分配函数的实现(1)-主体分配函数

原标题:Linux页框分配函数的实现(1)-主体分配函数

内核中有六个基本的页框分配函数,它们内部经过封装,最终都会调用alloc_pages_node()。这个函数的参数比alloc_pages()多了一个nid,它用来指定节点id,如果nid小于0,则说明在当前节点上分配页框。正确获取到节点id后,接下来调用__alloc_pages()。

static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order){ if (nid < 0) nid = numa_node_id(); return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));}

__alloc_pages()第三个参数根据nid和gfp_mask得到适当的zonelist链表,该过程通过node_zonelist()完成。该函数的实现比较简单,其中NODE_DATA()根据nid返回对应的内存节点描述符,而gfp_zonelist()根据flags标志选取对应的内存管理区链表。其实node_zonelist()就是根据flags在相应内存节点的node_zonelists数组中选择一个何时的内存管理区链表zonelist。

static inline int gfp_zonelist(gfp_t flags){ if (NUMA_BUILD && unlikely(flags & __GFP_THISNODE)) return 1; return 0;}

由于node_zonelists数组的元素个数最大为2,因此gfp_zonelist()返回0或者1。如果flags中设置了__GFP_THISNODE并且NUMA被设置,则表明使用当前节点对应的zonelist,返回1。否则使用备用zonelist,也就是说当本地节点中zone不足时,在其他节点中申请页框。

static inline int gfp_zonelist(gfp_t flags){ if (NUMA_BUILD && unlikely(flags & __GFP_THISNODE)) return 1; return 0;}

alloc_pages()内部再次封装alloc_pages_nodemask()。

static inline struct page *__alloc_pages(gfp_t gfp_mask, unsigned int order, struct zonelist *zonelist){ return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);} 1. 主体分配函数

现在进入__alloc_pages_nodemask(),它作为页框分配函数的核心部分。该函数可以通过get_page_from_freelist()快速分配所请求的内存,但是大多数情况下调用该函数都会失败,因为通常物理内存的使用情况都比较紧张,这一点从其后if语句中的unlikely就可以看出。

struct page *__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,struct zonelist *zonelist, nodemask_t *nodemask){ enum zone_type high_zoneidx = gfp_zone(gfp_mask); struct zone *preferred_zone; struct page *page; int migratetype = allocflags_to_migratetype(gfp_mask); gfp_mask &= gfp_allowed_mask; lockdep_trace_alloc(gfp_mask); might_sleep_if(gfp_mask & __GFP_WAIT); if (should_fail_alloc_page(gfp_mask, order)) return NULL; if (unlikely(!zonelist->_zonerefs->zone)) return NULL; first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone); if (!preferred_zone) return NULL; page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order, zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET, preferred_zone, migratetype); if (unlikely(!page)) page = __alloc_pages_slowpath(gfp_mask, order, zonelist, high_zoneidx, nodemask, preferred_zone, migratetype); trace_mm_page_alloc(page, order, gfp_mask, migratetype); return page;}

首先,gfp_zone()根据gfp_mask选取适当类型的zone。在经过几项参数检查后,该函数通过zonelist->_zonerefs->zone判断zonelist是否为空,既至少需要一个zone可用。接着根据一开始选取的zone类型high_zoneidx,通过first_zones_zonelist()确定优先分配内存的内存管理区。

如果一切顺利,将会进入get_page_from_freelist(),这个函数可以看作是伙伴算法的前置函数,它通过分配标志和分配阶判断是否能进行此次内存分配。如果可以分配,则它进行实际的内存分配工作,既利用伙伴算法进行分配内存。否则,进入__alloc_pages_slowpath(),此时内核需要放宽一些分配条件,或回收一些系统的内存,然后再调用几次get_page_from_freelist()以申请所需内存。返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值