内存区管理中slab分配器的分配slab对象的函数kmem_cache_alloc():
void * kmem_cache_alloc (kmem_cache_t *cachep, int flags)
{
return __cache_alloc(cachep, flags);
}
__cache_alloc()函数实现对slab对象的分配:
static inline void * __cache_alloc (kmem_cache_t *cachep, int flags)
{
unsigned long save_flags;
void* objp;
struct array_cache *ac;
cache_alloc_debugcheck_before(cachep, flags);
local_irq_save(save_flags);
ac = ac_data(cachep);
if (likely(ac->avail)) {
STATS_INC_ALLOCHIT(cachep);
ac->touched = 1;
objp = ac_entry(ac)[--ac->avail];
} else {
STATS_INC_ALLOCMISS(cachep);
objp = cache_alloc_refill(cachep, flags);
}
local_irq_restore(save_flags);
objp = cache_alloc_debugcheck_after(cachep, flags, objp, __builtin_return_address(0));
return objp;
}
其中的语句objp = ac_entry(ac)[--ac->avail];等价于objp = ((void **)(ac+1))[--ac->avail];刚开始对于这个语句很不理解,后来查看了牛人对于slab相关数据结构的讲解,才恍然大悟。下图为slab相关的数据结构的图解:
要理解上述的那条语句需要注意以下3点:
(1)array_cache数据结构是空闲对象的本地高速缓存的一个描述符;
(2)而本地高速缓存数组是由一个指向被释放对象的小指针数组组成;
(3)本地高速缓存正好存放在array_cache描述符的后面。
所以((void **)(ac+1))[--ac->avail] 语句首先是通过ac+1来获取本地高速缓存的地址,由于本地高速缓存是一个包含指针的数组,所以要通过强制类型转换将ac类型转换为指向指针类型的指针。最后还要注意一点array_cache数据结构的 avail 域既表示本地高速缓存中可使用对象的指针的个数,也表示高速缓存中第一个空槽的下标。