四、slab内存的申请


内核代码中通过slab分配对象的函数时kmem_cachep_alloc(),实质上最后调用的函数是____cache_alloc(),其相应源码解析如下:

  1. static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)   
  2. {   
  3.     void *objp;   
  4.     struct array_cache *ac;   
  5.    
  6.     check_irq_off();   
  7.     //通过进程所在的cpu的id获取slab的本地高速缓存   
  8.     ac = cpu_cache_get(cachep);   
  9.     //本地高速缓存中是否有空闲的slab对象   
  10.     if (likely(ac->avail)) {   
  11.         //有空闲对象的话,从本地高速缓存数组上取一个空闲的对象来使用   
  12.         STATS_INC_ALLOCHIT(cachep);   
  13.         //标记一下该本地高速缓存最近被使用过   
  14.         ac->touched = 1;   
  15.         //从数组的最后面先取一个未使用的对象,HOHO   
  16.         objp = ac->entry[--ac->avail];   
  17.     } else {   
  18.         STATS_INC_ALLOCMISS(cachep);   
  19.         //本地高速缓存中已经没有空闲对象,需要填充本地高速缓存   
  20.         objp = cache_alloc_refill(cachep, flags);   
  21.     }   
  22.     return objp;   
  23. }   
  24.    
  25.     cache_alloc_refill()用来填充本地高速缓存,也是slab分配精华的地方,代码解析如下:   
  26. static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)   
  27. {   
  28.     int batchcount;   
  29.     struct kmem_list3 *l3;   
  30.     struct array_cache *ac;   
  31.    
  32.     check_irq_off();   
  33.     //根据cpu id得到slab本地高速缓存的数据结构   
  34.     ac = cpu_cache_get(cachep);   
  35. retry:   
  36.     //batchcount记录了此次需要填充多少个空闲对象   
  37.     batchcount = ac->batchcount;   
  38.     if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {   
  39.         batchcount = BATCHREFILL_LIMIT;   
  40.     }   
  41.     //获取到相对应的内存节点上的slab链表kmem_list3,每个内存节点都有自己的一套空闲,部分空闲,非空闲slab链表   
  42.     //因为相应cpu访问自己所属的内存节点的速度是最快的   
  43.     l3 = cachep->nodelists[numa_node_id()];   
  44.    
  45.     BUG_ON(ac->avail > 0 || !l3);   
  46.     spin_lock(&l3->list_lock);   
  47.    
  48.     //从本地共享高速缓存中往本地高速缓存中填充空闲对象,要注意对于numa   
  49.     //系统来说,往本地高速缓存上填充的空闲对象也都是该内存节点上的空闲对象   
  50.     if (l3->shared && transfer_objects(ac, l3->shared, batchcount))   
  51.         goto alloc_done;   
  52.    
  53.     while (batchcount > 0) {   
  54.         struct list_head *entry;   
  55.         struct slab *slabp;   
  56.         //先从部分空闲的slab里面分配空闲对象,保留完全空闲的slab,因为空闲的   
  57.         //slab在内存不足时是可以回收的   
  58.         entry = l3->slabs_partial.next;   
  59.         //如果没有了部分空闲的slab,就只能去完全空闲的slab中分配了   
  60.         if (entry == &l3->slabs_partial) {   
  61.             l3->free_touched = 1;   
  62.             entry = l3->slabs_free.next;   
  63.             //如果完全空闲的slab也没有了,就必须要为slab高速缓存分配新的slab了   
  64.             if (entry == &l3->slabs_free)   
  65.                 goto must_grow;   
  66.         }   
  67.    
  68.         slabp = list_entry(entry, struct slab, list);   
  69.         check_slabp(cachep, slabp);   
  70.         check_spinlock_acquired(cachep);   
  71.         //从slab中分配空闲对象,直到slab中空闲对象不存在了,或者已经分配   
  72.         //了足够的空闲对象了   
  73.         while (slabp->inuse < cachep->num && batchcount--) {   
  74.             STATS_INC_ALLOCED(cachep);   
  75.             STATS_INC_ACTIVE(cachep);   
  76.             STATS_SET_HIGH(cachep);   
  77.             //此处获取空闲对象   
  78.             ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,   
  79.                                 numa_node_id());   
  80.         }   
  81.         check_slabp(cachep, slabp);   
  82.    
  83.         /* move slabp to correct slabp list: */   
  84.         list_del(&slabp->list);   
  85.         //若相应slab的空闲内存分配完毕,将其挂入slabs_full的slab链表中   
  86.         if (slabp->free == BUFCTL_END)   
  87.             list_add(&slabp->list, &l3->slabs_full);   
  88.         else   
  89.             list_add(&slabp->list, &l3->slabs_partial);   
  90.     }   
  91.    
  92. must_grow:   
  93.     l3->free_objects -ac->avail;   
  94. alloc_done:   
  95.     spin_unlock(&l3->list_lock);   
  96.     //没有分配到任何的对象   
  97.     if (unlikely(!ac->avail)) {   
  98.         int x;   
  99.         //为高速缓存申请新的slab   
  100.         x = cache_grow(cachep, flags, numa_node_id());   
  101.    
  102.         /* cache_grow can reenable interrupts, then ac could change. */   
  103.         ac = cpu_cache_get(cachep);   
  104.         if (!x && ac->avail == 0)    /* no objects in sight? abort */   
  105.             return NULL;   
  106.         //重新从头填充本地高速缓存   
  107.         if (!ac->avail)      /* objects refilled by interrupt? */   
  108.             goto retry;   
  109.     }   
  110.     ac->touched = 1;   
  111.     //返回本地高速缓存最后一个空闲对象的地址   
  112.     return ac->entry[--ac->avail];   
  113. }   


相关内容