Linux内核源代码情景分析-内存管理之slab-分配与释放

    首先说缓存区的数据结构:

struct kmem_cache_s {
/* 1) each alloc & free */
	/* full, partial first, then free */
	struct list_head	slabs;//指向所有的slab块链表,前面是完全块,然后是非完全块,最后是空闲块
	struct list_head	*firstnotfull;//指向第一个非完全块,如果没有非完全块,就指向上面的slabs
	unsigned int		objsize;//对象的大小
	unsigned int	 	flags;	/* constant flags */
	unsigned int		num;	//对象的数量
	spinlock_t		spinlock;
#ifdef CONFIG_SMP
	unsigned int		batchcount;
#endif

/* 2) slab additions /removals */
	/* order of pgs per slab (2^n) */
	unsigned int		gfporder;//对象的页面数2 ^ gfporder

	/* force GFP flags, e.g. GFP_DMA */
	unsigned int		gfpflags;

	size_t			colour;		/* cache colouring range */
	unsigned int		colour_off;	/* colour offset */
	unsigned int		colour_next;	/* cache colouring */
	kmem_cache_t		*slabp_cache;
	unsigned int		growing;
	unsigned int		dflags;		/* dynamic flags */

	/* constructor func */
	void (*ctor)(void *, kmem_cache_t *, unsigned long);//构造函数

	/* de-constructor func */
	void (*dtor)(void *, kmem_cache_t *, unsigned long);//析构函数

	unsigned long		failures;

/* 3) cache creation/removal */
	char			name[CACHE_NAMELEN];//名字
	struct list_head	next;//链接下一个缓冲区
}
    

    再说slab块的数据结构:

typedef struct slab_s {
	struct list_head	list;           //链接下个slab块
	unsigned long		colouroff;      //当前slab块中的第一个对象距离slab块所在页面的页面边界位置的偏移量
	void			*s_mem;		//指向此slab块中的第一个对象的指针,等于页面边界位置+colouroff
	unsigned int		inuse;		//被使用的对象的数目
	kmem_bufctl_t		free;           //当前第一个空闲对象在此数组中的下标
} slab_t;


    我们主要研究on_slab的方法,针对于小对象。看完了数据结构,我们结合图再来理解下slab块。


                                                          图   1


    我们看到上图,有一个kmem_bufctl_t类型数组。起初被赋值为1,2,3,4.....,slab中free字段赋值为0。表示第一个可供分配的是第0个对象,随后free被赋值为kmem_bufctl_t类型数组[0] = 1,表示下次第1个对象是可供分配的。


                                                         图  2

    刚才缓冲区的colour_next ,colour_off,colour我们都没有解释,这里结合图2解释一下。其中页面偏移量实际上是缓存区的colour_next * colour_off得到的。colour_next 初始化为0,当colour_next达到colour时,会被重新置0。colour_off一般被赋值为L1_CACHE_BYTES,colour被赋值为slab块剩余空间/colour_off。


    整体框图如下:


                                                                                                                       图 3                                   


    完全slab块在前面,非完全或者说部分slab块放在中间,空闲slab块放到最后。通过kmem_cache_s的slabs,和slab_s的list链接成双向链表。kmem_cache_s的firstnotfull指向第一个非完全slab块。

    每个slab块都是 2 ^ gfporder个页面。


    下面我结合一个例子,来分析slab块的分配与释放

    1、创建缓存区,kmem_cache_create

kmem_cache_t *
kmem_cache_create (const char *name, size_t size, size_t offset,
	unsigned long flags, void (*ctor)(void*, kmem_cache_t *, unsigned long),
	void (*dtor)(void*, kmem_cache_t *, unsigned long))
{
	const char *func_nm = KERN_ERR "kmem_create: ";
	size_t left_over, align, slab_size;
	kmem_cache_t *cachep = NULL;

	/*
	 * Sanity checks... these are all serious usage bugs.
	 */
	if ((!name) ||
		((strlen(name) >= CACHE_NAMELEN - 1)) ||
		in_interrupt() ||
		(size < BYTES_PER_WORD) ||
		(size > (1<<MAX_OBJ_ORDER)*PAGE_SIZE) ||
		(dtor && !ctor) ||
		(offset < 0 || offset > size))
			BUG();
        ......

	......
	if (flags & ~CREATE_MASK)
		BUG();

	/* Get cache's description obj. */
	cachep = (kmem_cache_t *) kmem_cache_alloc(&cache_cache, SLAB_KERNEL);//分配缓存区
	if (!cachep)
		goto opps;
	memset(cachep, 0, sizeof(kmem_cache_t));//将缓存区清0

	......
	if (size & (BYTES_PER_WORD-1)) {//将size进行字对齐
		size += (BYTES_PER_WORD-1);
		size &= ~(BYTES_PER_WORD-1);
		printk("%sForcing size word alignment - %s\n", func_nm, name);
	}
	
        ......
	align = BYTES_PER_WORD;
	if (flags & SLAB_HWCACHE_ALIGN)//调整align
		align = L1_CACHE_BYTES;

	/* Determine if the slab management is 'on' or 'off' slab. */
	if (size >= (PAGE_SIZE>>3))
		.......
		flags |= CFLGS_OFF_SLAB;//我们假定现在是on_slab模式

	if (flags & SLAB_HWCACHE_ALIGN) {
		......
		while (size < align/2)
			align /= 2;
		size = (size+align-1)&(~(align-1));//调整size
	}

	......
	do {
		unsigned int break_flag = 0;
cal_wastage:
		kmem_cache_estimate(cachep-&g
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值