Linux内存管理之slab机制(释放对象)
Linux内存管理之slab机制(释放对象)
Linux内核中将对象释放到slab中上层所用函数为kfree()或kmem_cache_free()。两个函数都会调用__cache_free()函数。代码执行流程:
1,当本地CPU cache中空闲对象数小于规定上限时,只需将对象放入本地CPU cache中;
2,当local cache中对象过多(大于等于规定上限),需要释放一批对象到slab三链中。由函数cache_flusharray()实现。
1)如果三链中存在共享本地cache,那么首先选择释放到共享本地cache中,能释放多少是多少;
2)如果没有shared local cache,释放对象到slab三链中,实现函数为free_block()。对于free_block()函数,当三链中的空闲对象数过多时,销毁此cache。不然,添加此slab到空闲链表。因为在分配的时候我们看到将slab结构从cache链表中脱离了,在这里,根据page描述符的lru找到slab并将它添加到三链的空闲链表中。
主实现
- /*
- * Release an obj back to its cache. If the obj has a constructed state, it must
- * be in this state _before_ it is released. Called with disabled ints.
- */
- static inline void __cache_free(struct kmem_cache *cachep, void *objp)
- {
- /* 获得本CPU的local cache */
- struct array_cache *ac = cpu_cache_get(cachep);
- check_irq_off();
- kmemleak_free_recursive(objp, cachep->flags);
- objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
- kmemcheck_slab_free(cachep, objp, obj_size(cachep));
- /*
- * Skip calling cache_free_alien() when the platform is not numa.
- * This will avoid cache misses that happen while accessing slabp (which
- * is per page memory reference) to get nodeid. Instead use a global
- * variable to skip the call, which is mostly likely to be present in
- * the cache.
- *//* NUMA相关 */
- if (nr_online_nodes > 1 && cache_free_alien(cachep, objp))
- return;
- if (likely(ac->avail < ac->limit)) {
- /* local cache中的空闲对象数小于上限时
- ,只需将对象释放回entry数组中 */
- STATS_INC_FREEHIT(cachep);
- ac->entry[ac->avail++] = objp;
- return;
- } else {
- /* 大于等于上限时, */
- STATS_INC_FREEMISS(cachep);
- /* local cache中对象过多,需要释放一批对象到slab三链中。*/
- cache_flusharray(cachep, ac);
- ac->entry[ac->avail++] = objp;
- }
- }
释放对象到三链中
- /*local cache中对象过多,需要释放一批对象到slab三链中。*/
- static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
- {
- int batchcount;
- struct kmem_list3 *l3;
- int node = numa_node_id();
- /* 每次释放多少个对象 */
- batchcount = ac->batchcount;
- #if DEBUG
- BUG_ON(!batchcount || batchcount > ac->avail);
- #endif
- check_irq_off();
- /* 获得此cache的slab三链 */
- l3 = cachep->nodelists[node];
- spin_lock(&l3->list_lock);
- if (l3->shared) {
- /* 如果存在shared local cache,将对象释放到其中 */
- struct array_cache *shared_array = l3->shared;
- /* 计算shared local cache中还有多少空位 */
- int max = shared_array->limit - shared_array->avail;
- if (max) {
- /* 空位数小于要释放的对象数时,释放数等于空位数 */
- if (batchcount > max)
- batchcount = max;
- /* 释放local cache前面的几个对象到shared local cache中
- ,前面的是最早不用的 */
- memcpy(&(shared_array->entry[shared_array->avail]),
- ac->entry, sizeof(void *) * batchcount);
- /* 增加shared local cache可用对象数 */
- shared_array->avail += batchcount;
- goto free_done;
- }
- }
- /* 无shared local cache,释放对象到slab三链中 */
- free_block(cachep, ac->entry, batchcount, node);
- free_done:
- #if STATS
- {
- int i = 0;
- struct list_head *p;
- p = l3->slabs_free.next;
- while (p != &(l3->slabs_free)) {
- struct slab *slabp;
- slabp = list_entry(p, struct slab, list);
- BUG_ON(slabp->inuse);
- i++;
- p = p->next;
- }
- STATS_SET_FREEABLE(cachep, i);
- }
- #endif
- spin_unlock(&l3->list_lock);
- /* 减少local cache可用对象数*/
- ac->avail -= batchcount;
- /* local cache前面有batchcount个空位,将后面的对象依次前移batchcount位 */
- memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail);
- }
|
评论暂时关闭