内核版本:linux-2.6.11
-
内存区和内存对象
伙伴系统是linux用于满足对不同大小块内存分配和释放请求的解决方案,它为slab分配器提供页框分配请求的实现。
如果我们需要请求具有连续物理地址和任意长度的内存单元序列时,即不定大小的内存区时,则需要在伙伴系统之上提供一层更细粒度的管理方案。
Linux在分配内存的时候,会将这部分内存初始化成一定的类型,即内存对象,例如信号、进程描述符、文件描述符等等,在释放的时候,会进行析构。
然而进行初始化和析构占用的时间已然超出了分配这部分内存的时间,于是,需要一个机制能够省略内存初始化和内存析构的时间,这对提升内存从分配到使用再到释放这一系列处理过程的性能有着莫大帮助。
-
slab分配器
出于这两种需求,slab出现了。
slab分配器最早是由Jeff Bonwick引进Solaris 5.4内核中的,如今各主流Unix-like系统都在使用。
它充当了伙伴系统和内存区分配接口之间的中间件。
举一个完整的例子,假设之前没有任何可用高速缓存的情况下,slab分配器接收到第一个内存分配请求时,首先会调用伙伴系统来分配足够大小的页框,然后按照一定规则初始化这部分内存,返回。内存释放时,slab分配器不会马上析构这部分内存,而是标记为可用,下一次的内存分配请求如果类型相同,那么直接使用可用的未析构的那块内存区,这样一来,高速缓存中会留有相同类型内存区的可用链表,只要链表不为空,那么该类型的内存区分配请求将会跳过初始化这一步直接得到满足。
所以说整个slab分配器的核心就是缓存(硬件高速缓存),是一种用空间换时间的聪明机制。
-
高速缓存
kmem_cache_init()kmem_cache_sizes_init()
static void cache_init_objs(struct kmem_cache *cachep, struct page *page)
{
for (i = 0; i < cachep->num; i++) {
void *objp = index_to_obj(cachep, page, i);
if (cachep->ctor)
cachep->ctor(objp);
set_obj_status(page, i, OBJECT_FREE);
set_free_obj(page, i, i);
}
}
总结一下
首先,系统初始化了两组高速缓存,第一组包括各个指定类型(task_struct、mm_struct、singal等等)的高速缓存,第二组则是一系列2的幂字节大小的通用对象(范围从32-131072)的高速缓存,内核其他模块进行内存区分配请求时,指定好自己需要的内存类型所对应的高速缓存,例如,新建进程时就需要指定第一组中的task_struct对应高速缓存,kmalloc函数则是指定第二组中的高速缓存,slab分配器会取得指定高速缓存中的一个空闲内存对象返回给请求模块。
slab分配器在做分配和释放内存对象的工作时,会尽量减少构造新对象和析构旧对象以实现这个空间换时间的算法。
PS: 有什么问题,请各位一定指出,万分感谢。