Linux内存管理--slab及其代码解析(1)(3)
四、slab内存的申请
内核代码中通过slab分配对象的函数时kmem_cachep_alloc(),实质上最后调用的函数是____cache_alloc(),其相应源码解析如下:
- static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
- {
- void *objp;
- struct array_cache *ac;
- check_irq_off();
- //通过进程所在的cpu的id获取slab的本地高速缓存
- ac = cpu_cache_get(cachep);
- //本地高速缓存中是否有空闲的slab对象
- if (likely(ac->avail)) {
- //有空闲对象的话,从本地高速缓存数组上取一个空闲的对象来使用
- STATS_INC_ALLOCHIT(cachep);
- //标记一下该本地高速缓存最近被使用过
- ac->touched = 1;
- //从数组的最后面先取一个未使用的对象,HOHO
- objp = ac->entry[--ac->avail];
- } else {
- STATS_INC_ALLOCMISS(cachep);
- //本地高速缓存中已经没有空闲对象,需要填充本地高速缓存
- objp = cache_alloc_refill(cachep, flags);
- }
- return objp;
- }
- cache_alloc_refill()用来填充本地高速缓存,也是slab分配精华的地方,代码解析如下:
- static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
- {
- int batchcount;
- struct kmem_list3 *l3;
- struct array_cache *ac;
- check_irq_off();
- //根据cpu id得到slab本地高速缓存的数据结构
- ac = cpu_cache_get(cachep);
- retry:
- //batchcount记录了此次需要填充多少个空闲对象
- batchcount = ac->batchcount;
- if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
- batchcount = BATCHREFILL_LIMIT;
- }
- //获取到相对应的内存节点上的slab链表kmem_list3,每个内存节点都有自己的一套空闲,部分空闲,非空闲slab链表
- //因为相应cpu访问自己所属的内存节点的速度是最快的
- l3 = cachep->nodelists[numa_node_id()];
- BUG_ON(ac->avail > 0 || !l3);
- spin_lock(&l3->list_lock);
- //从本地共享高速缓存中往本地高速缓存中填充空闲对象,要注意对于numa
- //系统来说,往本地高速缓存上填充的空闲对象也都是该内存节点上的空闲对象
- if (l3->shared && transfer_objects(ac, l3->shared, batchcount))
- goto alloc_done;
- while (batchcount > 0) {
- struct list_head *entry;
- struct slab *slabp;
- //先从部分空闲的slab里面分配空闲对象,保留完全空闲的slab,因为空闲的
- //slab在内存不足时是可以回收的
- entry = l3->slabs_partial.next;
- //如果没有了部分空闲的slab,就只能去完全空闲的slab中分配了
- if (entry == &l3->slabs_partial) {
- l3->free_touched = 1;
- entry = l3->slabs_free.next;
- //如果完全空闲的slab也没有了,就必须要为slab高速缓存分配新的slab了
- if (entry == &l3->slabs_free)
- goto must_grow;
- }
- slabp = list_entry(entry, struct slab, list);
- check_slabp(cachep, slabp);
- check_spinlock_acquired(cachep);
- //从slab中分配空闲对象,直到slab中空闲对象不存在了,或者已经分配
- //了足够的空闲对象了
- 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,
- numa_node_id());
- }
- check_slabp(cachep, slabp);
- /* move slabp to correct slabp list: */
- list_del(&slabp->list);
- //若相应slab的空闲内存分配完毕,将其挂入slabs_full的slab链表中
- 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;
- //为高速缓存申请新的slab
- x = cache_grow(cachep, flags, numa_node_id());
- /* cache_grow can reenable interrupts, then ac could change. */
- ac = cpu_cache_get(cachep);
- if (!x && ac->avail == 0) /* no objects in sight? abort */
- return NULL;
- //重新从头填充本地高速缓存
- if (!ac->avail) /* objects refilled by interrupt? */
- goto retry;
- }
- ac->touched = 1;
- //返回本地高速缓存最后一个空闲对象的地址
- return ac->entry[--ac->avail];
- }
评论暂时关闭