slab分配器是Linux内存管理中非常重要和复杂的一部分,其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内碎片,而且处理速度也太慢。而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统。slab分配对象时,会使用最近释放的对象内存块,因此其驻留在CPU高速缓存的概率较高。
用于描述和管理cache的数据结构是struct kmem_cache:
-
struct kmem_cache {
-
/* 1) per-cpu data, touched during every alloc/free */
-
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; // buff_size的倒数值
-
/* 3) touched by every alloc & free from the backend */
-
-
unsigned int flags; /* constant flags */ // 高速缓存的永久标识
-
unsigned int num; /* # of objs per slab */ // 一个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; /* cache colouring range */ // 颜色个数
-
unsigned int colour_off; /* colour offset */ // 着色偏移量
-
struct kmem_cache *slabp_cache; // 如果将slab描述符存储在外部, 指针指向存储slab描述符的cache,否则为NULL
-
unsigned int slab_size; // slab管理区大小
-
unsigned int dflags; /* dynamic flags */ // 动态标识
-
-
/* 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 *nodelists[MAX_NUMNODES]; // 用于组织该高速缓存中的slab
-
/*
-
* Do not add fields after nodelists[]
-
*/
-
};
-
/*
-
* The slab lists for all objects.
-
*/
-
struct kmem_list3 {
-
struct list_head slabs_partial; /* partial list first, better asm code */ // 包含空闲和已分配对象的slab描述符
-
struct list_head slabs_full; // 包含非空闲的slab描述符
-
struct list_head slabs_free; // 包含空闲的slab描述符
-
unsigned long free_objects; // 高速缓存中空闲对象的个数
-
unsigned int free_limit; // 空闲对象的上限
-
unsigned int colour_next; /* Per-node cache coloring */ // 下一个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
-
*
-
* Manages the objs in a slab. Placed either at the beginning of mem allocated
-
* for a slab, or allocated from an general cache.
-
* Slabs are chained into three list: fully used, partial, fully free slabs.
-
*/
-
struct slab {
-
struct list_head list; // 用于将slab链入kmem_list3的链表
-
unsigned long colouroff; // 该slab的着色偏移
-
void *s_mem; /* including colour offset */ // 指向slab中的第一个对象
-
unsigned int inuse; /* num of objs active in slab */ // 已分配出去的对象
-
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
-
*
-
* Purpose:
-
* - LIFO ordering, to hand out cache-warm objects from _alloc
-
* - reduce the number of linked list operations
-
* - reduce spinlock operations
-
*
-
* The limit is stored in the per-cpu structure to reduce the data cache
-
* footprint.
-
*
-
*/
-
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分配器的工作之前,必须先理解上述这些数据结构之间的联系,下图给出了一个清晰的描述。
阅读(932) | 评论(0) | 转发(0) |