Linux Slub分配器(二)--初始化

水平有限,描述不当之处还请之处,转载请注明出处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);
}



你可能感兴趣的:(Linux Slub分配器(二)--初始化)