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并将它添加到三链的空闲链表中。

主实现

  1. /* 
  2.  * Release an obj back to its cache. If the obj has a constructed state, it must 
  3.  * be in this state _before_ it is released.  Called with disabled ints. 
  4.  */  
  5. static inline void __cache_free(struct kmem_cache *cachep, void *objp)  
  6. {  
  7.     /* 获得本CPU的local cache */  
  8.     struct array_cache *ac = cpu_cache_get(cachep);  
  9.   
  10.     check_irq_off();  
  11.     kmemleak_free_recursive(objp, cachep->flags);  
  12.     objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));  
  13.   
  14.     kmemcheck_slab_free(cachep, objp, obj_size(cachep));  
  15.   
  16.     /* 
  17.      * Skip calling cache_free_alien() when the platform is not numa. 
  18.      * This will avoid cache misses that happen while accessing slabp (which 
  19.      * is per page memory  reference) to get nodeid. Instead use a global 
  20.      * variable to skip the call, which is mostly likely to be present in 
  21.      * the cache. 
  22.      *//* NUMA相关 */  
  23.     if (nr_online_nodes > 1 && cache_free_alien(cachep, objp))  
  24.         return;  
  25.   
  26.     if (likely(ac->avail < ac->limit)) {  
  27.         /* local cache中的空闲对象数小于上限时 
  28.         ,只需将对象释放回entry数组中 */  
  29.         STATS_INC_FREEHIT(cachep);  
  30.         ac->entry[ac->avail++] = objp;  
  31.         return;  
  32.     } else {  
  33.         /* 大于等于上限时, */  
  34.         STATS_INC_FREEMISS(cachep);  
  35.         /* local cache中对象过多,需要释放一批对象到slab三链中。*/  
  36.         cache_flusharray(cachep, ac);  
  37.         ac->entry[ac->avail++] = objp;  
  38.     }  
  39. }  

释放对象到三链中

  1. /*local cache中对象过多,需要释放一批对象到slab三链中。*/  
  2. static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)  
  3. {  
  4.     int batchcount;  
  5.     struct kmem_list3 *l3;  
  6.     int node = numa_node_id();  
  7.     /* 每次释放多少个对象 */  
  8.     batchcount = ac->batchcount;  
  9. #if DEBUG   
  10.     BUG_ON(!batchcount || batchcount > ac->avail);  
  11. #endif   
  12.     check_irq_off();  
  13.     /* 获得此cache的slab三链 */  
  14.     l3 = cachep->nodelists[node];  
  15.     spin_lock(&l3->list_lock);  
  16.     if (l3->shared) {  
  17.         /* 如果存在shared local cache,将对象释放到其中 */  
  18.         struct array_cache *shared_array = l3->shared;  
  19.         /* 计算shared local cache中还有多少空位 */  
  20.         int max = shared_array->limit - shared_array->avail;  
  21.         if (max) {  
  22.             /* 空位数小于要释放的对象数时,释放数等于空位数 */  
  23.             if (batchcount > max)  
  24.                 batchcount = max;  
  25.             /* 释放local cache前面的几个对象到shared local cache中 
  26.             ,前面的是最早不用的 */  
  27.             memcpy(&(shared_array->entry[shared_array->avail]),  
  28.                    ac->entry, sizeof(void *) * batchcount);  
  29.             /* 增加shared local cache可用对象数 */  
  30.             shared_array->avail += batchcount;  
  31.             goto free_done;  
  32.         }  
  33.     }  
  34.     /* 无shared local cache,释放对象到slab三链中 */  
  35.     free_block(cachep, ac->entry, batchcount, node);  
  36. free_done:  
  37. #if STATS   
  38.     {  
  39.         int i = 0;  
  40.         struct list_head *p;  
  41.   
  42.         p = l3->slabs_free.next;  
  43.         while (p != &(l3->slabs_free)) {  
  44.             struct slab *slabp;  
  45.   
  46.             slabp = list_entry(p, struct slab, list);  
  47.             BUG_ON(slabp->inuse);  
  48.   
  49.             i++;  
  50.             p = p->next;  
  51.         }  
  52.         STATS_SET_FREEABLE(cachep, i);  
  53.     }  
  54. #endif   
  55.     spin_unlock(&l3->list_lock);  
  56.     /* 减少local cache可用对象数*/  
  57.     ac->avail -= batchcount;  
  58.     /* local cache前面有batchcount个空位,将后面的对象依次前移batchcount位 */  
  59.     memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void *)*ac->avail);  
  60. }  
  • 1
  • 2
  • 下一页

相关内容