Skip to content

Latest commit

 

History

History
155 lines (125 loc) · 4.26 KB

2014-05-13-slab-alloc.md

File metadata and controls

155 lines (125 loc) · 4.26 KB
layout title category description tags
post
slab分配
内存管理
slab分配...
slab

slab的分配使用kmem_cache_alloc函数,这个函数的流程图如下:

slab

<mm/slab.c>

{% highlight c++%} void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) { void *ret = __cache_alloc(cachep, flags, __builtin_return_address(0));

trace_kmem_cache_alloc(_RET_IP_, ret,
               obj_size(cachep), cachep->buffer_size, flags);

return ret;

} EXPORT_SYMBOL(kmem_cache_alloc); {% endhighlight %}

可以看到无论是kmalloc或者kmem_cache_alloc最后都会调用到*__cache_alloc函数,而__cache_alloc最后都会调用到____cache_alloc*函数1

<mm/slab.c>

{% highlight c++%} static inline void *____cache_alloc( struct kmem_cache *cachep, gfp_t flags) { void *objp; struct array_cache *ac;

check_irq_off();

ac = cpu_cache_get(cachep);
if (likely(ac->avail)) {
    STATS_INC_ALLOCHIT(cachep);
    ac->touched = 1;
    objp = ac->entry[--ac->avail];
} else {
    STATS_INC_ALLOCMISS(cachep);
    objp = cache_alloc_refill(cachep, flags);
}

kmemleak_erase(&ac->entry[ac->avail]);
return objp;

} {% endhighlight %}

从上面的代码来看,cachep是一个指针,指向缓存使用的kmem_cache_t实例,ac_data宏通过返回cachep->array[smp_processor_id()],从而获得当前活动CPU相关的array_cache实例。

因为内存中的对象紧跟array_cache实例之后,内核可以借助该结构末尾的伪数组访问对象而不需要使用指针,通过将ac->avail减去1,就可以将对象从缓存中移除。

如果在per-CPU中没有对象的话,就需要调用cache_alloc_refill方法来重新填充。

<mm/slab.c>

{% highlight c++%} static void *cache_alloc_refill( struct kmem_cache *cachep, gfp_t flags) { int batchcount; struct kmem_list3 *l3; struct array_cache *ac; int node;

retry: check_irq_off(); node = numa_node_id(); ac = cpu_cache_get(cachep); batchcount = ac->batchcount; if (!ac->touched && batchcount > BATCHREFILL_LIMIT) { /* 检查batchcount的值 */ batchcount = BATCHREFILL_LIMIT; } l3 = cachep->nodelists[node];

BUG_ON(ac->avail > 0 || !l3);
spin_lock(&l3->list_lock);

/* 检查是否可以从共享数组中重新填充 */
if (l3->shared && transfer_objects(
    ac, l3->shared, batchcount))
    goto alloc_done;

while (batchcount > 0) {
    struct list_head *entry;
    struct slab *slabp;
    /* 获取对象的slab链表 */
    entry = l3->slabs_partial.next;
    /* 首先是slabs_partial,然后是slabs_free */
    if (entry == &l3->slabs_partial) {
        l3->free_touched = 1;
        entry = l3->slabs_free.next;
        if (entry == &l3->slabs_free)
            goto must_grow;
    }

    slabp = list_entry(entry, struct slab, list);
    check_slabp(cachep, slabp);
    check_spinlock_acquired(cachep);

    /*
     * 如果slab不在partial或者free连表中
     * 那么至少有一个对象可以被分配
     */
    BUG_ON(slabp->inuse >= cachep->num);

    while (slabp->inuse < cachep->num && batchcount--) {
        STATS_INC_ALLOCED(cachep);
        STATS_INC_ACTIVE(cachep);
        STATS_SET_HIGH(cachep);

        ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,
                            node);
    }
    check_slabp(cachep, slabp);

    /* 将slab移动到正确的slab连表中 */
    list_del(&slabp->list);
    if (slabp->free == BUFCTL_END)
        list_add(&slabp->list, &l3->slabs_full);
    else
        list_add(&slabp->list, &l3->slabs_partial);
}

must_grow: l3->free_objects -= ac->avail; alloc_done: spin_unlock(&l3->list_lock);

if (unlikely(!ac->avail)) {
    int x;
    x = cache_grow(
        cachep, flags | GFP_THISNODE,
        node, NULL);

    ac = cpu_cache_get(cachep);
    if (!x && ac->avail == 0)
        return NULL;

    if (!ac->avail)
        goto retry;
}
ac->touched = 1;
return ac->entry[--ac->avail];

} {% endhighlight %}

Footnotes

  1. 四个下划线。