Linux内存储器管理 Slab分配器(二:初始化)

Linux内存管理 Slab分配器(二:初始化)

初看起来,slab系统的初始化不是特别麻烦,因为伙伴系统已经完全启用,内核没有受到其他特别的限制。尽管如此,由于slab分配器的结构所致,这里有一个鸡与蛋的问题。为初始化slab数据结构,内核需要若干远小于一整页的内存块,这些最适合由kmalloc分配。这里是关键所在:只有在slab系统已经启用之后,才能使用kmalloc。更确切的说,该问题涉及kmalloc的Per-CPU缓存的初始化。在这些缓存能初始化之前,kmalloc必须可以用来分配所需的内存空间,而kmalloc自身也处于初始化的过程中,所以这是一个不可能完成的场景,内核必须借助一些技巧。内核中使用kmem_cache_init函数用于初始化slab分配器。它在内核初始化阶段(start_kernel)、伙伴系统启用之后调用。kmem_cache_init采用了一个多步骤的过程,逐步激活slab分配器。

kmem_cache_init可以分为六个阶段:
第一个阶段:是根据kmem_cache来设置cache_cache的字段值;
第二个阶段:首先是创建arraycache_init对应的高速缓存,同时也是在这个kmem_cache_create的调用过程中,创建了用于保存cache的kmem_cache的slab,并初始化了slab中的各个对象;
第三个阶段:创建kmem_list3对应的高速缓存,在这里要注意的一点是,如果sizeof(arraycache_t)和sizeof(kmem_list3)的大小一样大,那么就不再使用kmem_cache_create来为kmem_list3创建cache了,因为如果两者相等的话,两者就可以使用同一个cache;
第四个阶段:创建并初始化所有的通用cache和dma cache;
第五个阶段:创建两个arraycache_init对象,分别取代cache_cache中的array字段和malloc_sizes[INDEX_AC].cs_cachep->array字段;
第六个阶段:创建两个kmem_list3对象,取代cache_cache中的kmem_list3字段和malloc_sizes[INDEX_AC].cs_cachep->nodelist3字段.如此一来,经过上面的六个阶段后,所有的初始化工作基本完成了。

kmem_cache_init源代码详细分析如下:

void __init kmem_cache_init(void)
{
size_t left_over;
struct cache_sizes *sizes;
struct cache_names *names;
int i;
int order;
int node;
/* 在slab初始化好之前,无法通过kmalloc分配初始化过程中必要的一些对象 ,只能使用静态的全局变量
,待slab初始化后期,再使用kmalloc动态分配的对象替换全局变量 */

/* 如前所述,先借用全局变量initkmem_list3表示的slab三链
,每个内存节点对应一组slab三链。initkmem_list3是个slab三链数组,对于每个内存节点,包含三组
:struct kmem_cache的slab三链、struct arraycache_init的slab 三链、struct kmem_list3的slab三链 。这里循环初始化所有内存节点的所有slab三链 */
if (num_possible_nodes() == 1) {
use_alien_caches = 0;
numa_platform = 0;
}

for (i = 0; i < NUM_INIT_LISTS; i++) {//初始化所有node的所有slab中的三个链表
kmem_list3_init(&initkmem_list3[i]);
if (i < MAX_NUMNODES)
cache_cache.nodelists[i] = NULL;//全局静态变量cache_cache,这个变量是用来管理所有缓存的kmem_cache的, 也就是说,在初始化阶段,将会创建一个slab,用来存放所有缓存的kmem_cache
}

/*
* Fragmentation resistance on low memory - only use bigger
* page orders on machines with more than 32MB of memory.
*/
if (num_physpages > (32 << 20) >> PAGE_SHIFT)//num_physpages是记录系统实际存在物理内存的总页数,如果大于32M
slab_break_gfp_order = BREAK_GFP_ORDER_HI;//才可以创建高阶指数内存页数的高速缓存内存对象

/* Bootstrap is tricky, because several objects are allocated
* from caches that do not exist yet:
* 1) initialize the cache_cache cache: it contains the struct
* kmem_cache structures of all caches, except cache_cache itself:
* cache_cache is statically allocated.
* Initially an __init data area is used for the head array and the
* kmem_list3 structures, it's replaced with a kmalloc allocated
* array at the end of the bootstrap.
* 2) Create the first kmalloc cache.
* The struct kmem_cache for the new cache is allocated normally.
* An __init data area is used for the head array.
* 3) Create the remaining kmalloc caches, with minimally sized
* head arrays.
* 4) Replace the __init data head arrays for cache_cache and the first
* kmalloc cache with kmalloc allocated arrays.
* 5) Replace the __init data for kmem_list3 for cache_cache and
* the other cache's with kmalloc allocated memory.
* 6) Resize the head arrays of the kmalloc caches to their final sizes.
*/

node = numa_node_id();//获取当前的内存结点号

//第一步,创建struct kmem_cache所在的cache,由全局变量cache_cache指向,这里只是初始化数据结构,并未真正创建这些对象,要待分配时才创建。全局变量cache_chain是内核slab cache链表的表头
INIT_LIST_HEAD(&cache_chain);//初始化保存所有slab cache的全局链表cache_chain
list_add(&cache_cache.next, &cache_chain);//将cache_cache加入到slab cache链表
cache_cache.colour_off = cache_line_size();//设置cache着色基本单位为cache line的大小:32字节
cache_cache.array[smp_processor_id()] = &initarray_cache.cache;//初始化cache_cache的local cache,同样这里也不能使用kmalloc,需要使用静态分配的全局变量initarray_cache
cache_cache.nodelists[node] = &initkmem_list3[CACHE_C

Linux内存储器管理 Slab分配器(二:初始化)

相关文章:

你感兴趣的文章:

标签云: