Linux内存分配系统

本文深入剖析了Linux内核的内存管理机制,重点介绍了伙伴系统和slab分配器。伙伴系统以页为单位进行内存分配和回收,通过空闲链表和合并策略高效管理内存。slab分配器针对不同大小的对象,提供更细粒度的内存分配,通过多级缓存提高分配速度。此外,还提及了vmalloc在高端内存分配中的作用。
摘要由CSDN通过智能技术生成

上一篇我们从内存结点,内存域的维度查看了Linux内存管理。本篇接着从内存分配的维度来看Linux内存管理。到现在为止,内核建立起了节点,域,页三级管理结构,并完成了页表映射。但是这一切都是在启动期内存管理器的基础上建立的,我们自建的内存管理器只完成了内存映射,还不具备内存分配的功能。为此接下来内核需要建立内存分配系统,Linux从内存分配效率,内存利用率的角度出发在前述管理结构上建立起hubby子系统来对接内存页分配,但是这还不够,考虑到系统中各种可能的对象尺寸和内存分配效率,Linux在hubby子系统的基础上构建起slab内存分配器来满足系统各种尺寸对象的分配需求,同时结合硬件缓存实现内存的高速分配。

一. 伙伴系统

Linux在构建起分页管理后,内存管理的责任由伙伴系统承担。每一个内存域都关联了一个struct zone,该结构中的free_area数组用于管理伙伴系统数据。free_area数组的索引即是内存页分配阶数,最大阶数MAX_ORDER=11,即2048页。

在这里插入图片描述

linux_kernel/include/linux/mmzone.h

struct zone {
   
	struct free_area	free_area[];
}

结构体free_area的free_list为对应阶数的内存页连表数组,该数组按内存页的迁移类型MIGRATE_TYPES来区分。nr_free统计空闲页数目。

linux_kernel/include/linux/mmzone.h

struct free_area {
   
	struct list_head	free_list[MIGRATE_TYPES];
	unsigned long		nr_free;
};

1.分配

linux_kernel/include/linux/gfp.h

static inline struct page *
__alloc_pages(gfp_t gfp_mask, unsigned int order, int preferred_nid)
{
   
	return __alloc_pages_nodemask(gfp_mask, order, preferred_nid, NULL);
}

linux_kernel/mm/page_alloc.c
伙伴系统核心分配函数

struct page *
__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,
							nodemask_t *nodemask)
{
   
	struct page *page;
	//尝试从空闲链表分配
	page = get_page_from_freelist(alloc_mask, order, alloc_flags, &ac);
	if (likely(page))
		goto out;
	//走慢分配
	page = __alloc_pages_slowpath(alloc_mask, order, &ac);

out:
	return page;
}
EXPORT_SYMBOL(__alloc_pages_nodemask);

linux_kernel/mm/page_alloc.c
遍历所有备用zone,尝试从空闲列表分配

static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
						const struct alloc_context *ac)
{
   
    ......
	for_next_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,
								ac->nodemask) {
   
		......
		page = rmqueue(ac->preferred_zoneref->zone, zone, order,
				gfp_mask, alloc_flags, ac->migratetype);
	    ......
	   
		}
	}
	return NULL;
}

linux_kernel/mm/page_alloc.c
按迁移类型遍历内存域

static inline
struct page *rmqueue(struct zone *preferred_zone,
			struct zone *zone, unsigned int order,
			gfp_t gfp_flags, unsigned int alloc_flags,
			int migratetype)
{
   
	page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC);
	return page;
}

linux_kernel/mm/page_alloc.c
找到合适的空闲页返回

static __always_inline
struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
						int migratetype)
{
   
	unsigned int current_order;
	struct free_area *area;
	struct page *page;

	/* Find a page of the appropriate size in the preferred list */
	for (current_order = order; current_order < MAX_ORDER; ++current_order) {
   
		area = &(zone->free_area[current_order]);
		page = get_page_from_free_area(area, migratetype);
		if (!page)
			continue;
		del_page_from_free_area(page, area);
		expand(zone, page, order, current_order, area, migratetype);
		set_pcppage_migratetype(page, migratetype);
		return page;
	}

	return NULL;
}

2.回收

linux_kernel/mm/page_alloc.c

void __free_pages(struct page *page, unsigned int order)
{
   
	if (put_page_testzero(page))
		free_the_page(page, order);
}
EXPORT_SYMBOL(__free_pages);

linux_kernel/mm/page_alloc.c
如果是单页,不归还给伙伴系统,放到CPU缓存中

static inline void free_the_page(struct page *page, unsigned int order)
{
   
	if (order == 0)
		free_unref_page(page); //释放单页
	else
		__free_pages_ok(page, order);
}

linux_kernel/mm/page_alloc.c
计算内存页对应的内存域,迁移类型

static void __free_pages_ok(struct page *page, unsigned int order)
{
   
	free_one_page(page_zone(page), page, pfn, order, migratetype);
}

linux_kernel/mm/page_alloc.c

static void free_one_p
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值