Linux Slub分配器(六)--slab的分配与释放

水平有限,描述不当之处还请之处,转载请注明出处http://blog.csdn.net/vanbreaker/article/details/7702677

创建新的slab主要有两个工作,一个是从伙伴系统分配2^order个连续页框给该slab,然后就是划分slab中的对象。

函数new_slab()用来创建一个新的slab.

static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
	struct page *page;
	void *start;
	void *last;
	void *p;

	BUG_ON(flags & GFP_SLAB_BUG_MASK);

	/*为待创建的slab分配页框*/
	page = allocate_slab(s,
		flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
	if (!page)
		goto out;
	
    /*增加slab计数*/
	inc_slabs_node(s, page_to_nid(page), page->objects);

	page->slab = s;//设置页描述符的slab指针
	page->flags |= 1 << PG_slab;//为页框增加一个slab属性
	if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
			SLAB_STORE_USER | SLAB_TRACE))
		__SetPageSlubDebug(page);

	/*获取页框的虚拟地址*/
	start = page_address(page);

	if (unlikely(s->flags & SLAB_POISON))
		memset(start, POISON_INUSE, PAGE_SIZE << compound_order(page));

	last = start;
	for_each_object(p, s, start, page->objects) {
		setup_object(s, page, last);//调用构造函数
		set_freepointer(s, last, p); //设置空闲指针,即last后面的空闲对象为p
		last = p;
	}
	setup_object(s, page, last);
	set_freepointer(s, last, NULL);  //最后一个对象的空闲指针设为NULL

	/*设置page的freelist和inuse*/
	page->freelist = start;
	page->inuse = 0;
out:
	return page;
}

static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
{
	struct page *page;
	struct kmem_cache_order_objects oo = s->oo;
	gfp_t alloc_gfp;

	flags |= s->allocflags;

	/*
	 * Let the initial higher-order allocation fail under memory pressure
	 * so we fall-back to the minimum order allocation.
	 */
	 /*确定gfp标识*/
	alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL;

	/*分配页框*/
	page = alloc_slab_page(alloc_gfp, node, oo);

	/*如果分配失败,则按min的标准进行分配*/
	if (unlikely(!page)) {
		oo = s->min;
		/*
		 * Allocation may have failed due to fragmentation.
		 * Try a lower order alloc if possible
		 */
		page = alloc_slab_page(flags, node, oo);
		if (!page)
			return NULL;

		stat(get_cpu_slab(s, raw_smp_processor_id()), ORDER_FALLBACK);
	}

	if (kmemcheck_enabled
		&& !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
		int pages = 1 << oo_order(oo);

		kmemcheck_alloc_shadow(page, oo_order(oo), flags, node);

		/*
		 * Objects from caches that have a constructor don't get
		 * cleared when they're allocated, so we need to do it here.
		 */
		if (s->ctor)
			kmemcheck_mark_uninitialized_pages(page, pages);
		else
			kmemcheck_mark_unallocated_pages(page, pages);
	}

	
	page->objects = oo_objects(oo);//从oo中提取出slab中的对象数放到保存到page的objects中
	mod_zone_page_state(page_zone(page),
		(s->flags & SLAB_RECLAIM_ACCOUNT) ?
		NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
		1 << oo_order(oo));

	return page;
}


函数alloc_slab_page()便是Slub分配器与伙伴系统的接口!

static inline struct page *alloc_slab_page(gfp_t flags, int node,
					struct kmem_cache_order_objects oo)
{
	int order = oo_order(oo);//从oo中提取出分配阶数

	flags |= __GFP_NOTRACK;

	/*从伙伴系统中分配2^order个连续页框*/
	if (node == -1)
		return alloc_pages(flags, order);
	else
		return alloc_pages_node(node, flags, order);
}



获得了所需的页框后,接下来就是在这些页框中划分对象,将他们全部组织起来

for_each_object(p, s, start, page->objects) {
		setup_object(s, page, last);//调用构造函数
		set_freepointer(s, last, p); //设置空闲指针,即last后面的空闲对象为p
		last = p;
	}


#define for_each_object(__p, __s, __addr, __objects) \
	for (__p = (__addr); __p < (__addr) + (__objects) * (__s)->size;\
			__p += (__s)->size)


static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
	/*注意kmem_cache中的offset是以字节为单位的*/
	*(void **)(object + s->offset) = fp;
}


初始化后的对象如下图所示

销毁slab通过函数discard_slab()来完成

static void discard_slab(struct kmem_cache *s, struct page *page)
{
	/*减少节点的slab计数和对象计数*/
	dec_slabs_node(s, page_to_nid(page), page->objects);
	free_slab(s, page);//释放slab
}

static void free_slab(struct kmem_cache *s, struct page *page)
{
	if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
		/*
		 * RCU free overloads the RCU head over the LRU
		 */
		struct rcu_head *head = (void *)&page->lru;

		call_rcu(head, rcu_free_slab);//通过RCU方式来释放
	} else
		__free_slab(s, page);//将slab所占页框释放回伙伴系统
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值