水平有限,描述不当之处还请之处,转载请注明出处http://blog.csdn.net/vanbreaker/article/details/7695264
和slab分配器一样,分配器的初始化工作主要是初始化用于kmalloc的gerneral cache,Slub分配器的gerneral cache定义如下:
struct kmem_cache kmalloc_caches[SLUB_PAGE_SHIFT] __cacheline_aligned;
#define SLUB_PAGE_SHIFT (PAGE_SHIFT + 2)
SLUB_PAGE_SHIFT的值为14,也就是说Slub分配器拥有14个gerneral cache,这14个gerneral cache的作用分别是什么呢?在NUMA架构下,下标为0的gc是用来存节点slab信息描述符的,也就是struct kmem_cache_node,UMA架构下,下标为0的gc被废弃。然后从下标为3的gc开始,缓存的对象大小从KMALLOC_MIN_SIZE开始按2的指数幂增长。那么下标为1和2的gc是用来做什么的呢?这两个gc是用来增加缓存的粒度的,下标为1的gc对应的缓存大小为96,下标为2的gc对应的缓存大小为192。当用kmalloc分配192字节以下的对象时,size_index数组用来选择在哪个gc中进行分配。
static s8 size_index[24] = { 3, /* 8 */ 4, /* 16 */ 5, /* 24 */ 5, /* 32 */ 6, /* 40 */ 6, /* 48 */ 6, /* 56 */ 6, /* 64 */ 1, /* 72 */ 1, /* 80 */ 1, /* 88 */ 1, /* 96 */ 7, /* 104 */ 7, /* 112 */ 7, /* 120 */ 7, /* 128 */ 2, /* 136 */ 2, /* 144 */ 2, /* 152 */ 2, /* 160 */ 2, /* 168 */ 2, /* 176 */ 2, /* 184 */ 2 /* 192 */ };
size_index数组中存储的是gc的编号,要根据对象大小来定位gc的方法很简单,直接用size/8 - 1即可。如要分配大小为48的对象,那么48/8 - 1=5,而size_index数组中下标5对应的偏移为6,在kmalloc_caches数组中,下标6对应的gc的对象大小为64,因此就找到了一个合理的gc,当然,以上的讨论都是基于KMALLOC_MIN_SIZES为8的情况下的。那么可想而知,gc的初始化工作主要就是创建gc以及建立size_index数组到gc之间的映射。
void __init kmem_cache_init(void)
{
int i;
int caches = 0;
init_alloc_cpu();
#ifdef CONFIG_NUMA
/*
* Must first have the slab cache available for the allocations of the
* struct kmem_cache_node's. There is special bootstrap code in
* kmem_cache_open for slab_state == DOWN.
*/
/*创建kmalloc_caches的第0个缓存用来存储struct kmem_cache_node*/
create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node",
sizeof(struct kmem_cache_node), GFP_NOWAIT);
kmalloc_caches[0].refcount = -1;
caches++;
hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
#endif
/* Able to allocate the per node structures */
slab_state = PARTIAL;//将初始化进度改为PARTIAL,表示已经可以分配struct kmem_cache_node
/* Caches that are not of the two-to-the-power-of size */
/*如果kmalloc的最小对象大小不大于32则创建第1个缓存,对象大小为96字节*/
if (KMALLOC_MIN_SIZE <= 32) {
create_kmalloc_cache(&kmalloc_caches[1],
"kmalloc-96", 96, GFP_NOWAIT);
caches++;
}
/*如果kmalloc的最小对象大小不大于64则创建第2个缓存,对象大小为192字节*/
if (KMALLOC_MIN_SIZE <= 64) {
create_kmalloc_cache(&kmalloc_caches[2],
"kmalloc-192", 192, GFP_NOWAIT);
caches++;
}
/*创建后续的普通缓存*/
for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
create_kmalloc_cache(&kmalloc_caches[i],
"kmalloc", 1 << i, GFP_NOWAIT);
caches++;
}
/*
* Patch up the size_index table if we have strange large alignment
* requirements for the kmalloc array. This is only the case for
* MIPS it seems. The standard arches will not generate any code here.
*
* Largest permitted alignment is 256 bytes due to the way we
* handle the index determination for the smaller caches.
*
* Make sure that nothing crazy happens if someone starts tinkering
* around with ARCH_KMALLOC_MINALIGN
*/
/*这里做一些必要的检查,保证kmalloc允许的最小对象的大小不能大于256
并且该值必须是2的整数幂*/
BUILD_BUG_ON(KMALLOC_MIN_SIZE > 256 ||
(KMALLOC_MIN_SIZE & (KMALLOC_MIN_SIZE - 1)));
/*对于大小在8字节与KMALLOC_MIN_SIZE之间的对象,将其在size_index数组中的索引
设置为KMALLOC_SHIFT_LOW,也就是log(KMALLOC_MIN_SIZE),这些对象都将以KMALLOC_MIN_SIZE
大小进行分配*/
for (i = 8; i < KMALLOC_MIN_SIZE; i += 8) {
int elem = size_index_elem(i);
if (elem >= ARRAY_SIZE(size_index))
break;
size_index[elem] = KMALLOC_SHIFT_LOW;
}
/*如果KMALLOC_MIN_SIZE为64,则弃用96字节的缓存*/
if (KMALLOC_MIN_SIZE == 64) {
/*
* The 96 byte size cache is not used if the alignment
* is 64 byte.
*/
/*将72字节与96字节之间的对象子size_index数组中的索引设为7,
这些对象将以128字节进行分配*/
for (i = 64 + 8; i <= 96; i += 8)
size_index[size_index_elem(i)] = 7;
} else if (KMALLOC_MIN_SIZE == 128) {/*如果最小对象大小为128字节,则弃用192字节的缓存*/
/*
* The 192 byte sized cache is not used if the alignment
* is 128 byte. Redirect kmalloc to use the 256 byte cache
* instead.
*/
for (i = 128 + 8; i <= 192; i += 8)
size_index[size_index_elem(i)] = 8;
}
slab_state = UP;//更新初始化进度
/* Provide the correct kmalloc names now that the caches are up */
for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++)
kmalloc_caches[i]. name =
kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
#ifdef CONFIG_SMP
register_cpu_notifier(&slab_notifier);
/*计算kmem_cache的大小*/
kmem_size = offsetof(struct kmem_cache, cpu_slab) +
nr_cpu_ids * sizeof(struct kmem_cache_cpu *);
#else
kmem_size = sizeof(struct kmem_cache);
#endif
printk(KERN_INFO
"SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
" CPUs=%d, Nodes=%d\n",
caches, cache_line_size(),
slub_min_order, slub_max_order, slub_min_objects,
nr_cpu_ids, nr_node_ids);
}