水平有限,描述不當之處還請之處,轉載請註明出處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);
}