Linux Slab分配器--概述

slab分配器是Linux内存管理中非常重要和复杂的一部分,其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内碎片,而且处理速度也太慢。而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统。slab分配对象时,会使用最近释放的对象内存块,因此其驻留在CPU高速缓存的概率较高。

用于描述和管理cache的数据结构是struct kmem_cache。

struct kmem_cache {
/* 1) per-cpu data, touched during every alloc/free */
    /*per-CPU数据,记录了本地高速缓存的信息,也用于跟踪最近释放的对象,每次分配和释放都要直接访问它*/
	struct array_cache *array[NR_CPUS]; 
/* 2) Cache tunables. Protected by cache_chain_mutex */
	unsigned int batchcount;  /*本地高速缓存转入或转出的大批对象数量*/
	unsigned int limit;       /*本地高速缓存中空闲对象的最大数目*/
	unsigned int shared;
 
	unsigned int buffer_size;/*管理对象的大小*/
	u32 reciprocal_buffer_size;/*buffer_size的倒数值*/
/* 3) touched by every alloc & free from the backend */
 
	unsigned int flags;          /* 高速缓存的永久标识*/
	unsigned int num;		  /* 一个slab所包含的对象数目 */
 
/* 4) cache_grow/shrink */
	/* order of pgs per slab (2^n) */
	unsigned int gfporder;   /*一个slab包含的连续页框数的对数*/
 
	/* force GFP flags, e.g. GFP_DMA */
	gfp_t gfpflags;          /*与伙伴系统交互时所提供的分配标识*/
 
	size_t colour;	       /* 颜色的个数*/
	unsigned int colour_off; /* 着色的偏移量 */
	
	/*如果将slab描述符存储在外部,该指针指向存储slab描述符的cache,
	  否则为NULL*/
	struct kmem_cache *slabp_cache;
	unsigned int slab_size;  /*slab管理区的大小*/
	unsigned int dflags;     /*动态标识*/
 
	/* constructor func */
	void (*ctor)(void *obj); /*创建高速缓存时的构造函数指针*/
 
/* 5) cache creation/removal */
	const char *name;         /*高速缓存名*/
	struct list_head next;    /*用于将高速缓存链入cache chain*/
 
/* 6) statistics */
#ifdef CONFIG_DEBUG_SLAB /*一些用于调试用的变量*/
	unsigned long num_active;
	unsigned long num_allocations;
	unsigned long high_mark;
	unsigned long grown;
	unsigned long reaped;
	unsigned long errors;
	unsigned long max_freeable;
	unsigned long node_allocs;
	unsigned long node_frees;
	unsigned long node_overflow;
	atomic_t allochit;
	atomic_t allocmiss;
	atomic_t freehit;
	atomic_t freemiss;
 
	/*
	 * If debugging is enabled, then the allocator can add additional
	 * fields and/or padding to every object. buffer_size contains the total
	 * object size including these internal fields, the following two
	 * variables contain the offset to the user object and its size.
	 */
	int obj_offset;
	int obj_size;
#endif /* CONFIG_DEBUG_SLAB */
 
	/*
	 * We put nodelists[] at the end of kmem_cache, because we want to size
	 * this array to nr_node_ids slots instead of MAX_NUMNODES
	 * (see kmem_cache_init())
	 * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache
	 * is statically defined, so we reserve the max number of nodes.
	 */
	 /*struct kmem_list3用于组织该高速缓存中的slab*/
	struct kmem_list3 *nodelists[MAX_NUMNODES];
	/*
	 * Do not add fields after nodelists[]
	 */
};
struct kmem_list3 {
	struct list_head slabs_partial;/*slab链表,包含空闲对象和已分配对象的slab描述符*/
	struct list_head slabs_full;   /*slab链表,只包含非空闲的slab描述符*/
	struct list_head slabs_free;   /*slab链表,只包含空闲的slab描述符*/
	unsigned long free_objects;    /*高速缓存中空闲对象的个数*/
	unsigned int free_limit;       /*空闲对象的上限*/
	unsigned int colour_next;	    /*下一个slab使用的颜色*/
	spinlock_t list_lock;
	struct array_cache *shared;	/* shared per node */
	struct array_cache **alien;	/* on other nodes */
	unsigned long next_reap;	/* updated without locking */
	int free_touched;		/* updated without locking */
};

描述和管理单个slab的结构是struct slab.

struct slab {
	struct list_head list;  /*用于将slab链入kmem_list3的链表*/
	unsigned long colouroff;/*该slab的着色偏移*/
	void *s_mem;            /*指向slab中的第一个对象*/
	unsigned int inuse;     /*已分配出去的对象*/
	kmem_bufctl_t free;     /*下一个空闲对象的下标*/
	unsigned short nodeid;  /*节点标识号*/
};

还要介绍的一个数据结构就是struct array_cache。struct kmem_cache中定义了一个struct array_cache指针数组,数组的元素个数对应了系统的CPU数,和伙伴系统中的每CPU页框高速缓存类似,该结构用来描述每个CPU的本地高速缓存,它可以减少SMP系统中对于自旋锁的竞争。在每个array_cache的末端都用一个指针数组记录了slab中的空闲对象,分配对象时,采用LIFO方式,也就是将该数组中的最后一个索引对应的对象分配出去,以保证该对象还驻留在高速缓存中的可能性。实际上,每次分配内存都是直接与本地CPU高速缓存进行交互,只有当其空闲内存不足时,才会从kmem_list中的slab中引入一部分对象到本地高速缓存中,而kmem_list中的空闲对象也不足了,那么就要从伙伴系统中引入新的页来建立新的slab了,这一点也和伙伴系统的每CPU页框高速缓存很类似。

struct array_cache {
	unsigned int avail;/*本地高速缓存中可用的空闲对象数*/
	unsigned int limit;/*空闲对象的上限*/
	unsigned int batchcount;/*一次转入和转出的对象数量*/
	unsigned int touched;   /*标识本地CPU最近是否被使用*/
	spinlock_t lock;
	void *entry[];	/*这是一个伪数组,便于对后面用于跟踪空闲对象的指针数组的访问
			 * Must have this definition in here for the proper
			 * alignment of array_cache. Also simplifies accessing
			 * the entries.
			 */
};

slab分配器涉及到了一些繁杂的概念,这些在后面再逐一结合代码进行讲解,在理解slab分配器的工作之前,必须先理解上述这些数据结构之间的联系,下图给出了一个清晰的描述。
在这里插入图片描述

发布了44 篇原创文章 · 获赞 54 · 访问量 33万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览