slub释放过程-do_slab_free

do_slab_free

一、快速路径

if (likely(page == c->page)) {
        void **freelist = READ_ONCE(c->freelist);

        set_freepointer(s, tail_obj, freelist);

        if (unlikely(!this_cpu_cmpxchg_double(
                        s->cpu_slab->freelist, s->cpu_slab->tid,
                        freelist, tid,
                        head, next_tid(tid)))) {

               note_cmpxchg_failure("slab_free", s, tid);
               goto redo;
        }
        stat(s, FREE_FASTPATH);
} else
        __slab_free(s, page, head, tail_obj, cnt, addr);
1、要释放的对象正好在cpu本地缓存中;
2、set_freepointer函数:将要释放的object加入到空闲的object链表中,并且为链表中代替freelist为第一个空闲的object,即相当于object->next = c->freelist;
3、重新分配freelist,这里是将c->freelist = head(head即目标object);

slub释放过程-do_slab_free

二、慢速路径

进入__slab_free函数,大致框架如下:

do {
        if (unlikely(n)) {
                spin_unlock_irqrestore(&n->list_lock, flags);
                n = NULL;
        }
        prior = page->freelist;
        counters = page->counters;
        set_freepointer(s, tail, prior);
        new.counters = counters;
    	/*
    	 * 1、frozen=0,说明该slab在node中;frozen=1,则说明该slab在slab_cpu缓存中;
    	 * 2、inuse=0,说明该slab中没有正在使用的object;inuse=objects,则说明该slab为full
    	 * 3、prior=0,说明目标object在c->page中或者在s->slab_cpu->partital、
    	      s->node->partital中且无可分配的object
    	 */
        was_frozen = new.frozen;
        new.inuse -= cnt;
    	/*
    	 * 下面需要对目标object释放的情况进行划分:
    	 * (1)inuse=0 && was_frozen=0:目标object在node节点中,且释放后该slab中的object			   全部未分配,此时该slab可以释放到伙伴系统或者不处理;
    	 * (2)prior=0 && was_frozen=0:释放前在full的slab链表中,释放后为半满状态;
    	 * (3)was_frozen=1:该slab在s->slab_cpu->partital缓存中;
    	 */
		if ((!new.inuse || !prior) && !was_frozen) {             //(1)(2)
				if (kmem_cache_has_cpu_partial(s) && !prior) {   //(2)
						new.frozen = 1;
                } else {                                         //(1)
                    	n = get_node(s, page_to_nid(page));
                    	spin_lock_irqsave(&n->list_lock, flags);
                }
} while (!cmpxchg_double_slab(s, page,
        prior, counters,
        head, new.counters,
        "__slab_free"));
/* 
 * 前面的while循环中对目标object释放进行了分类和简单的预处理,下面针对这几种情况进行后续的处理。
 * 包括是否将空的slab释放回伙伴系统以及维护slab_cpu->patital和node->partital链表;
 */


if (likely(!n)) {
    	if (new.frozen && !was_frozen) {    //(2)node节点,半满
                put_cpu_partial(s, page, 1);//将slab释放到slab_cpu->partital链表中
                stat(s, CPU_PARTIAL_FREE);
        }
		if (was_frozen)                     //slab_cpu->partital中,则不处理直接返回
            	stat(s, FREE_FROZEN);
    	return;
}
//释放object后该slab变为free,此时需要对比node->partital中slab的数量和内核定义的最小min大小
//如果n->nr_partial >= s->min_partial,则将slab释放到伙伴系统;
//如果n->nr_partial <  s->min_partial, 则不处理;
if (unlikely(!new.inuse && n->nr_partial >= s->min_partial))
    	goto slab_empty;

//未定义CONFIG_SLUB_CPU_PARTITAL时走这个流程;
if (!kmem_cache_has_cpu_partial(s) && unlikely(!prior)) {
    	remove_full(s, n, page);//从full链表中移除
    	add_partial(n, page, DEACTIVATE_TO_TAIL);//加入到node->partital链表中
    	stat(s, FREE_ADD_PARTIAL);
}
spin_unlock_irqrestore(&n->list_lock, flags);
return;
slab_empty:
        if (prior) {
                /*
                 * Slab on the partial list.
                 */
                remove_partial(n, page);//将该slab从链表中删除,并将nr_partital减一
                stat(s, FREE_REMOVE_PARTIAL);
        } else {
                /* Slab must be on the full list */
                remove_full(s, n, page);
        }
        spin_unlock_irqrestore(&n->list_lock, flags);
        stat(s, FREE_SLAB);
        discard_slab(s, page);
}

所以从代码来看,主要分成以下几种情况:

1、目标object在s->slab_cpu->partital中,直接释放即可,无需后续的处理;

slub释放过程-do_slab_free

2、目标object在s->node中,释放完object后slab中的object全为free;此时需要考虑空的slab如何处理

(1)s->node->partital中slab的个数大于等于min_partital时,将该slab释放到伙伴系统;

(2)s->node->partital中slab的个数小于min_partital时,该slab依然保留在s->node->partital链表中;

3、目标object在s->node中,释放object前slab为full,没有可分配object,释放完后为半满状态;此时需要将半满的slab从full链表中删除并加入到s->slab_cpu的链表中,需要注意s->slab_cpu->partital中也需要判断下所有的free的object的数量是否超过了规定的水位,判断后在决定是否加入;

lab从full链表中删除并加入到s->slab_cpu的链表中,需要注意s->slab_cpu->partital中也需要判断下所有的free的object的数量是否超过了规定的水位,判断后在决定是否加入;

上一篇:内存管理基础(Linux内核涉及与实现)


下一篇:架构解密从分布式到微服务:深入浅析内存,内存缓存技术分析