STL中的空间配置器采用一、二级配置器进行内存管理,当配置区块
在一级配置器中,allocate()直接使用malloc(),deallocate()直接使用free(),对于内存不足的情况,模拟C++的set_new_handler()机制;
在二级配置器中,首先会维护16个自由链表(free lists),负责16种小型区块的次配置能力;如果内存不足,转调一级配置器中的set_new_handler()。如果请求内存块大于128bytes,就转调一级配置器。当请求内存块小于128bytes,则以内存池管理。
这里的free lists,即空闲链表,包含可供使用的、已经分配好的数据结构块。当代码需要一个新的数据结构实例时,就可以从空闲链表中抓取一个,而不需要分配内存,可以直接把数据放进去。当不再需要这个数据结构的实例时,就把它放回空闲链表,而不是释放它。
但是,空闲链表主要的问题是不能全局控制。当内存变得紧缺时,内核无法通知每个空闲链表,让其收缩缓存的大小以便释放出一些内存来。Linux内核为了弥补这一缺陷,增加了slab分配器。
slab分配器相当于通用数据结构缓存层,为具体对象类型分配。
slab分配器基本原则:
· 频繁使用的数据结构会频繁分配和释放,因此应当缓存。
· 频繁分配和回收会导致内存碎片。为了避免内存碎片现象,空闲链表的缓存会连续的存放。因为已释放的数据结构又会放会空闲链表,因此不会导致碎片。
· 回收的对象可以立即投入下一次分配。对于频繁的分配和释放,空闲链表能够提高其性能。
· 对存放的对象进行着色,以防止多个对象映射到相同的高速缓存行(cache line)。
· 如果分配器知道对象大小、页大小和总的高速缓存的大小,会更合适。
· 如果分配器是与NUMA相关的,就可以从相同的内存节点为请求者进行分配。(NUMA:非统一内存访问,遵循对称多处理(SMP)架构)
slab层的设计
slab是由一个或多个物理上连续的页组成。每个高速缓存可由多个slab。
slab层把不同的对象划分为所谓高速缓存组,其中每个高速缓存组都存放不同类型的对象。即每种对象类型对应一个高速缓存。 而且,kmalloc()接口建立在slab层上,使用了一组通用高速缓存。
每个高速缓存使用结构体kmem_cache表示。这个结构包含三个链表:slabs_full、slabs_partial、slabs_empty,均可放在kmem_list3结构中。该结构在mm/slab.c中定义。
struct kmem_cache_s {
/* 1) per-cpu data, touched during every alloc/free */
/**
* 每CPU指针数组,指向包含空闲对象的本地高速缓存。
*/
struct array_cache *array[NR_CPUS];
/**
* 要转移进本地高速缓存或从本地高速缓存中转移出的大批对象的数量。
*/
unsigned int batchcount;
/**
* 本地高速缓存中空闲对象的最大数目。这个参数可调。
*/
unsigned int limit;
/* 2) touched by every alloc & free from the backend */
/**
* 包含三个链表,为什么要单独放到一个描述符中呢?
*/
struct kmem_list3 lists;
/* NUMA: kmem_3list_t *nodelists[MAX_NUMNODES] */
/**
* 高速缓存中包含的对象的大小。
*/
unsigned int objsize;
/**
* 描述高速缓存永久属性的一组标志。
*/
unsigned int flags; /* constant flags */
/**
* 在一个单独slab中的对象的个数。高速缓存中的所有slab具有相同的大小。
*/
unsigned int num; /* # of objs per slab */
/**
* 整个slab高速缓存中空闲对象的上限。
*/
unsigned int free_limit; /* upper limit of objects in the lists */
/**
* 高速缓存自旋锁。
*/
spinlock_t spinlock;
/* 3) cache_grow/shrink */
/* order of pgs per slab (2^n) */
/**
* 一个单独slab中包含的连续页框数目的对数。
*/
unsigned int gfporder;
/* force GFP flags, e.g. GFP_DMA */
/**
* 分配页框时传递给伙伴系统函数的一组标志。
*/
unsigned int gfpflags;
/**
* slab使用的颜色个数。用于slab着色。
*/
size_t colour; /* cache colouring range */
/**
* slab中的基本对齐偏移。
*/
unsigned int colour_off; /* colour offset */
/**
* 下一个被分配的slab使用的颜色。就是对齐因子。
*/
unsigned int colour_next; /* cache colouring */
/**
* 指向包含slab描述符的普通slab高速缓存。如果使用了内部slab描述符,则这个字段为NULL。
*/
kmem_cache_t *slabp_cache;
/**
*