alloc_pages函数分析

alloc_pages函数是Linux内核中用于动态内存分配的关键函数。它首先通过alloc_pages_current调用__alloc_pages_nodemask,该函数涉及内存分配的条件检查、计算内存分配信息、碎片优化以及从空闲列表尝试分配。在分配失败时,会进入慢速路径__alloc_pages_slowpath进行处理。整个过程关注于高效且优化的内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

alloc_pages函数分析

static inline struct page *
alloc_pages(gfp_t gfp_mask, unsigned int order)
{
	return alloc_pages_current(gfp_mask, order);
}

alloc_pages 调用关系:

static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
    	struct page *alloc_pages_current(gfp_t gfp, unsigned order)
            	struct page *__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,nodemask_t *nodemask)                    

所以分析alloc_pages 的实现需要分析__alloc_pages_nodemask 这个函数.

__alloc_pages_nodemask:

unsigned int alloc_flags = ALLOC_WMARK_LOW;

1 允许分配内存的判断条件为低水位.

	if (unlikely(order >= MAX_ORDER)) {
		WARN_ON_ONCE(!(gfp_mask & __GFP_NOWARN));
		return NULL;
	}

2 伙伴系统最大内存块大小为2(MAX_ORDER-1) 个页面,如果MAX_ORDER = 11 ,一页大小为4K则最大内存块 4*1024k = 4M大小.

prepare_alloc_pages(gfp_mask, order, preferred_nid, nodemask, &ac, &alloc_mask, &alloc_flags)

prepare_alloc_pages 的功能计算相关的信息,并保存到ac 这个变量里面,ac 是一个*struct* alloc_context

struct alloc_context {
	struct zonelist *zonelist;
	nodemask_t *nodemask;
	struct zoneref *preferred_zoneref;
	int migratetype;
	enum zone_type high_zoneidx;
	bool spread_dirty_pages;
};
finalise_ac(gfp_mask, &ac);

3 使用finalise_ac 确定,首选的zone.

	alloc_flags |= alloc_flags_nofragment(ac.preferred_zoneref->zone, gfp_mask);

4 使用alloc_flags_nofragment 做内存碎片的优化.

static inline unsigned int
alloc_flags_nofragment(struct zone *zone, gfp_t gfp_mask)
{
	unsigned int alloc_flags = 0;

	if (gfp_mask & __GFP_KSWAPD_RECLAIM)
		alloc_flags |= ALLOC_KSWAPD;

#ifdef CONFIG_ZONE_DMA32
	if (zone_idx(zone) != ZONE_NORMAL)
		goto out;

	/*
	 * If ZONE_DMA32 exists, assume it is the one after ZONE_NORMAL and
	 * the pointer is within zone->zone_pgdat->node_zones[]. Also assume
	 * on UMA that if Normal is populated then so is DMA32.
	 */
	BUILD_BUG_ON(ZONE_NORMAL - ZONE_DMA32 != 1);
	if (nr_online_nodes > 1 && !populated_zone(--zone))
		goto out;

out:
#endif /* CONFIG_ZONE_DMA32 */
	return alloc_flags;
}

5 如果首选的zone是高端的zone,如ZONE_NORMAL ,过早的使用了低端的zone将会造成内存短缺的问题,所以当发生碎片化的时候应该尽可能的从ZONE_NORMAL 中的其它迁移内型链表中挪用一些空闲的内存,这样会比过早的使用低端的zone会好很多.

	page = get_page_from_freelist(alloc_mask, order, alloc_flags, &ac);
	if (likely(page))
		goto out;

使用get_page_from_freelist进行第一次分配尝试(空闲列表里面能够满足这次的分配需求),如果成功了,就直接返回内存块的第一个页面的page,当然如果分配失败了就使用下面这个函数

page = __alloc_pages_slowpath(alloc_mask, order, &ac);

进入慢速路径进行页面分配.

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DipsyHu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值