Linux Slub分配器(五)--释放对象

 

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

       释放对象和分配对象是一组对称的操作,同样分为两个路径:

1.如果待释放的对象所属的slab位于本地CPU缓存中,也就是slab处于冻结状态,则可直接释放

2.反之,待释放的对象所属的slab位于slab链表中,也就是slab处于解冻状态,则要通过慢速路径进行释放。

 

函数kmem_cache_free()用来将一个对象释放至对应的缓存中

void kmem_cache_free(struct kmem_cache *s, void *x)
{
	struct page *page;

	/*找到对象x所属slab的首页*/
	page = virt_to_head_page(x);

	/*释放对象x*/
	slab_free(s, page, x, _RET_IP_);

	trace_kmem_cache_free(_RET_IP_, x);
}


释放对象前必须先得到对象所属slab的第一个页,这样便于后面判断slab是否处于本地CPU缓存中。

static __always_inline void slab_free(struct kmem_cache *s,
			struct page *page, void *x, unsigned long addr)
{
	void **object = (void *)x;
	struct kmem_cache_cpu *c;
	unsigned long flags;

	kmemleak_free_recursive(x, s->flags);
	local_irq_save(flags);
	c = get_cpu_slab(s, smp_processor_id());//获取本地CPU的slab信息结构

	/*相关检查*/
	kmemcheck_slab_free(s, object, c->objsize);
	debug_check_no_locks_freed(object, c->objsize);
	if (!(s->flags & SLAB_DEBUG_OBJECTS))
		debug_check_no_obj_freed(object, c->objsize);

	/*这里必须确定待释放对象所属的slab的确还处于本地CPU中,因为在常规分配失败时
	  本地CPU中的slab可能会被解冻,也就是转移到slab链表中,而解冻时可能还有
	  对象未回收*/
	if (likely(page == c->page && c->node >= 0)) {
		/*释放的操作和分配的操作是对称的*/
		object[c->offset] = c->freelist; //设定空闲指针
		c->freelist = object;            //重置freelist
		stat(c, FREE_FASTPATH);
	} else
		__slab_free(s, page, x, addr, c->offset);//慢速释放路径

	local_irq_restore(flags);
}


判断slab是否位于本地CPU缓存中的方式很简单,就是看本地CPU缓存中的page指针和之前获取的page指针是否相等,相等的话就表明两者指向同一个page,也就是说是同一个slab. 判断node>=0是为了辨明该非调试状态,因为node==-1是用来调试的。常规释放路径和分配是对称的操作,如果看懂了分配,那么这个自然也就明白了,不赘述了。下面来看慢速释放路径

static void __slab_free(struct kmem_cache *s, struct page *page,
			void *x, unsigned long addr, unsigned int offset)
{
	void *prior;
	void **object = (void *)x;
	struct kmem_cache_cpu *c;

	
	c = get_cpu_slab(s, raw_smp_processor_id());
	stat(c, FREE_SLOWPATH);
	slab_lock(page);

	if (unlikely(SLABDEBUG && PageSlubDebug(page)))
		goto debug;

checks_ok:
	/*将对象释放回原属的slab*/
	prior = object[offset] = page->freelist;
	page->freelist = object;
	page->inuse--;

	if (unlikely(PageSlubFrozen(page))) {
		stat(c, FREE_FROZEN);
		goto out_unlock;
	}

	/*inuse为0表示该slab的所有对象都处于空闲状态*/
	if (unlikely(!page->inuse))
		goto slab_empty;

	/*
	 * Objects left in the slab. If it was not on the partial list before
	 * then add it.
	 */
	 /*prior为空表明之前page->freelist为NULL,也就是说slab没有处于partial slab链表中,
	   将该slab添加到partial slab链表的尾部*/
	if (unlikely(!prior)) {
		add_partial(get_node(s, page_to_nid(page)), page, 1);
		stat(c, FREE_ADD_PARTIAL);
	}

out_unlock:
	slab_unlock(page);
	return;

slab_empty:
	if (prior) {//prior不为空表明slab处于partial slab链表中
		/*
		 * Slab still on the partial list.
		 */
		remove_partial(s, page);//将slab从partial slab链表中删除
		stat(c, FREE_REMOVE_PARTIAL);
	}
	slab_unlock(page);
	stat(c, FREE_SLAB);
	discard_slab(s, page);//销毁slab
	return;

debug:
	if (!free_debug_processing(s, page, x, addr))
		goto out_unlock;
	goto checks_ok;
}

首先获取本地CPU缓存结构,保存在c中,然后将对象释放回slab,注意这里用的是page->freelist而不是c->freelist

如果page->inuse为0,表示slab所有对象都是空闲的,slub没有free list链表,因此选择直接销毁该slab,将内存返回给伙伴系统。如果prior为空,那也就表示slab处于full slab链表而不是partial slab链表,由于现在获得了一个空闲对象,因此将slab添加到partial slab中,至于从full slab中删除slab的操作,是在free_debug_processing()中完成的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值