slab源码分析--从slab初始化说起

来源:互联网 发布:免费数据恢复大师 编辑:程序博客网 时间:2024/04/28 00:07

上次说了 slab 的主要数据结构,这次从初始化开始进行源码剖析。

slab 的初始化,当然是从内核启动就开始了。内核启动的 start_kernel() 函数:

//内核的启动程序啊:)asmlinkage void __init start_kernel(void){    ...    mem_init();    //内存相关初始化    kmem_cache_init();    //slab 初始化    ...}

其中调用 kmem_cache_init() 函数,这就是要进行 slab 的初始化。

/* * Initialisation.  Called after the page allocator have been initialised and * before smp_init(). */ //这个函数用来建立通用缓存器,否则我们无法使用kmallocvoid __init kmem_cache_init(void){    size_t left_over;    struct cache_sizes *sizes;    struct cache_names *names;    int i;    int order;    int node;    //如果节点数目只有1个,那么就不能使用其他节点的shared cache    if (num_possible_nodes() == 1)  //貌似当前这个版本还不支持这个,参见#define num_possible_nodes() 1        use_alien_caches = 0;             //后续linux版本会支持    //在slab初始化好之前,无法通过kmalloc分配初始化过程中的一些必要对象,只能使用静态的全局变量    //待slab初始化后期,再使用kmalloc动态分配对象替换全局变量!!    //如前所述,先借用 initkem_list3 代替要用到的三链,每个节点对应一组三链    //initkmem_list3 是个三链数组,这里循环初始化每个节点的三链     for (i = 0; i < NUM_INIT_LISTS; i++) {       //FIXME: NUM_INIT_LIST 是怎么求的,为什么等于2 * MAX_NODES+1 ? 有的版本是 3 * MAX_NODES        kmem_list3_init(&initkmem_list3[i]);        if (i < MAX_NUMNODES)        //全局变量cache_cache指向的slab cache包含所有的kmem_cache对象,不包含cache_cache本身        //这里初始化所有内存节点kmem_cache的slab三链为空            cache_cache.nodelists[i] = NULL;    }    /*     * Fragmentation resistance on low memory - only use bigger     * page orders on machines with more than 32MB of memory.     */     //全部变量slab_break_gfp_order为每个slab最多占用几个页面,用来减少碎片。     //总结起来意思就是是: (1)如果物理可用内存大于32MB,也就是可用内存充裕的时候,BREAK_GFP_ORDER_HI这个宏的值是1,     //这个时候每个slab最多占用两个页面,不过此时不能横跨3个页面,除非对象大小大于8192K时才可以(一个页面大小是4K,也就是4096);     //(2)如果可用内存不大于32MB,那么BREAK_GFP_ORDER_HI值为0,最多也就是允许一个页面,除非对象超了,否则不能横跨    if (num_physpages > (32 << 20) >> PAGE_SHIFT)        slab_break_gfp_order = BREAK_GFP_ORDER_HI;   //用来确定slab的最大大小    /* 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();   //获取节点id,取得的值为0,因为初始化程序单CPU执行,且是0号    /* 1) create the cache_cache */    //初始化cache_chain 为 kmem_cache 链表头部    INIT_LIST_HEAD(&cache_chain);    list_add(&cache_cache.next, &cache_chain);    //设置cache着色的偏移量基本值,也就是L1缓存行的大小    cache_cache.colour_off = cache_line_size(); //宏定义L1缓存行的大小 #define cache_line_size() L1_CACHE_BYTES    //初始化cache_cache的per-CPU cache,同样这里也不能使用kmalloc,需要使用静态分配的全局变量initarray_cache    cache_cache.array[smp_processor_id()] = &initarray_cache.cache;    //初始化slab链表,用全局变量,这里CACHE_CACHE值为0,是因为cache_cache就是系统第一个的缓存器    cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];    /*     * struct kmem_cache size depends on nr_node_ids, which     * can be less than MAX_NUMNODES.     */     //buffer_size原指用来分配的对象大小,由于cache_cache是用来做 kmem_cache 的分配器的,所以 buffer_size 的大小就是 kmem_cache 的大小     //注意柔性数组的计算方法,nodelists不占据 kmem_cache的大小,所以要分开计算,并且注意nodelists数组在UMA架构只有一个节点,所以只有1个kmem_list3的指针    cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +                 nr_node_ids * sizeof(struct kmem_list3 *);#if 0 #if DEBUG    cache_cache.obj_size = cache_cache.buffer_size;#endif#endif    //注意这里又一次计算了 buffer_size 的大小,通过这次计算将buffer_size以 缓存行 为单位进行上边界对齐    //计算分配的对象与cache line的大小对齐后的大小    cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,                    cache_line_size());    //计算对象大小的倒数,用于计算对象在slab中的索引    cache_cache.reciprocal_buffer_size =        reciprocal_value(cache_cache.buffer_size);    //计算cache_cache的剩余空间以及slab中对象的数目,order决定了slab的大小(PAGE_SIZEE<<order)    for (order = 0; order < MAX_ORDER; order++) { //#define MAX_ORDER 11        cache_estimate(order, cache_cache.buffer_size,  //buffer_size已经和cache line对齐过            cache_line_size(), 0, &left_over, &cache_cache.num);  //计算cache_cache的对象数目        if (cache_cache.num) //num不为0意味着struct kmem_cache对象创建成功,退出,所以在此处就会确定order的大小,以赋值给gfporder            break;    }    BUG_ON(!cache_cache.num);  //断言    cache_cache.gfporder = order;  //gfporder表示本slab包含2^gfproder个页面,注意这里就从上面的order赋值给 gfporder    //colour_off 就是上面初始化的 L1_CACHE_BYTES,既然已经知道 L1 缓存行的大小,我们上步又计算出了浪费空间的大小    //那么用浪费空间的大小 / L1 缓存行的大小,就得出当前可用 colour 的数目,这个数目是累加且循环的,可以为0    cache_cache.colour = left_over / cache_cache.colour_off;   //确定可用 colour 的数目,单位是 colour_off    //确定slab描述符以及kmem_bufctl_t数组 针对缓存行对齐后的大小    cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +                        sizeof(struct slab), cache_line_size());    /* 2+3) create the kmalloc caches */    sizes = malloc_sizes;   //malloc_sizes数组保存着要分配的大小    names = cache_names;  //cache_name保存cache名    /*     * Initialize the caches that provide memory for the array cache and the     * kmem_list3 structures first.  Without this, further allocations will     * bug.     */    //首先创建struct array_cache 和 struct kmem_list3 所用的通用缓存器general cache,它们是后续初始化动作的基础    //INDEX_AC是计算local cache所用的struct arraycache_init对象在kmalloc size中的索引,即属于哪一级别大小的general cache,创建此大小级别的cache为local cache所用    sizes[INDEX_AC].cs_cachep = kmem_cache_create(names[INDEX_AC].name,                    sizes[INDEX_AC].cs_size,                    ARCH_KMALLOC_MINALIGN,                    ARCH_KMALLOC_FLAGS|SLAB_PANIC,   //#define ARCH_KMALLOC_FLAGS SLAB_HWCACHE_ALIGN,已经对齐过的标记                    NULL, NULL);    if (INDEX_AC != INDEX_L3) {    //如果struct kmem_list3 和 struct arraycache_init对应的kmalloc size索引不同,即大小属于不同的级别,    //则创建struct kmem_list3所用的cache,否则共用一个cache        sizes[INDEX_L3].cs_cachep =            kmem_cache_create(names[INDEX_L3].name,                sizes[INDEX_L3].cs_size,                ARCH_KMALLOC_MINALIGN,                ARCH_KMALLOC_FLAGS|SLAB_PANIC,                NULL, NULL);    }    slab_early_init = 0;//创建完上述两个通用缓存器后,slab early init阶段结束,在此之前,不允许创建外置式slab    //sizes->cs_size 初值为是malloc_sizes[0],值应该是从32开始    while (sizes->cs_size != ULONG_MAX) {  //循环创建kmalloc各级别的通用缓存器,ULONG_MAX 是最大索引值,        /*         * For performance, all the general caches are L1 aligned.         * This should be particularly beneficial on SMP boxes, as it         * eliminates(消除) "false sharing".         * Note for systems short on memory removing the alignment will         * allow tighter(紧的) packing of the smaller caches.         */        if (!sizes->cs_cachep) {               sizes->cs_cachep = kmem_cache_create(names->name,                    sizes->cs_size,                    ARCH_KMALLOC_MINALIGN,                    ARCH_KMALLOC_FLAGS|SLAB_PANIC,                    NULL, NULL);        }#ifdef CONFIG_ZONE_DMA   //如果配置DMA,那么为每个kmem_cache 分配两个,一个DMA,一个常规        sizes->cs_dmacachep = kmem_cache_create(                    names->name_dma,                    sizes->cs_size,                    ARCH_KMALLOC_MINALIGN,                    ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA|                        SLAB_PANIC,                    NULL, NULL);#endif        sizes++;   //都是数组名,直接++,进行循环迭代,由小到大分配各个大小的general caches,最大为ULONG_MAX        names++;    }    /* 4) Replace the bootstrap head arrays */    {        struct array_cache *ptr;        //现在要申请arraycache替换之前的initarray_cache        ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);  //GFP_KERNEL 可睡眠申请        //关中断        local_irq_disable();        BUG_ON(cpu_cache_get(&cache_cache) != &initarray_cache.cache);        memcpy(ptr, cpu_cache_get(&cache_cache),               sizeof(struct arraycache_init));  //将cache_cache中per-cpu对应的array_cache拷贝到ptr        /*         * Do not assume that spinlocks can be initialized via memcpy:         */        spin_lock_init(&ptr->lock);        cache_cache.array[smp_processor_id()] = ptr;  //再让它指向ptr?        local_irq_enable();        ptr = kmalloc(sizeof(struct arraycache_init), GFP_KERNEL);        local_irq_disable();        BUG_ON(cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep)               != &initarray_generic.cache);        memcpy(ptr, cpu_cache_get(malloc_sizes[INDEX_AC].cs_cachep),               sizeof(struct arraycache_init));        /*         * Do not assume that spinlocks can be initialized via memcpy:         */        spin_lock_init(&ptr->lock);        malloc_sizes[INDEX_AC].cs_cachep->array[smp_processor_id()] =            ptr;        local_irq_enable();    }    /* 5) Replace the bootstrap kmem_list3's */    {        int nid;        /* Replace the static kmem_list3 structures for the boot cpu */        init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node);        for_each_online_node(nid) {            init_list(malloc_sizes[INDEX_AC].cs_cachep,                  &initkmem_list3[SIZE_AC + nid], nid);            if (INDEX_AC != INDEX_L3) {                init_list(malloc_sizes[INDEX_L3].cs_cachep,                      &initkmem_list3[SIZE_L3 + nid], nid);            }        }    }    /* 6) resize the head arrays to their final sizes */    {        struct kmem_cache *cachep;        mutex_lock(&cache_chain_mutex);        list_for_each_entry(cachep, &cache_chain, next)            if (enable_cpucache(cachep)) //这个函数先暂时不剖析,是对本地缓存的处理                BUG();        mutex_unlock(&cache_chain_mutex);    }    /* Annotate slab for lockdep -- annotate the malloc caches */    init_lock_keys();    /* Done! */    g_cpucache_up = FULL;    /*     * Register a cpu startup notifier callback that initializes     * cpu_cache_get for all new cpus     */    register_cpu_notifier(&cpucache_notifier);    /*     * The reap timers are started later, with a module init call: That part     * of the kernel is not yet operational.     */}

这个函数就是 slab 初始化的主干。
执行流程:

  1. 使用 initkmem_list3 和 intarray_cache 两个静态量,再加上手动填充cache_cache 的其他变量 ,完成对 cache_cache 的初始化。这是用来缓存 kmem_cache 的,相当于是缓存器的缓存器:)
  2. 创建 kmalloc 所用的其他通用缓存器:
    1. cache 的名称和大小放在 names[] 和 malloc_sizes[] 两个数组中,对应大小的 cache 可以从 malloc_sizes[] 中找到,索引就是要分配对象的大小。
    2. 先创建 INDEX_AC 和 INDEX_L3 下标的 cache(array_cache 和 三链,如果大小一样,只创建一次)。
    3. 循环创建 size 数组中各个大小的 cache。
  3. 替换静态本地 cache 全局变量:
    1. 替换 malloc_sizes[INDEX_AC].cs_cachep 的 local cache,原本指向静态变量 initarray_cache.cache。
    2. 替换 malloc_sizes[INDEX_AC].cx_cachep 的 local cache,原本指向静态变量 initarray_generic.cache。 ( kmem_cache_create() 中调用 setup_cpu_cache() 函数会使用该静态变量)。
  4. 替换静态三链:
    1. 替换 cache_cache 三链,原本指向静态变量的 initkmem_list3。
    2. 替换 malloc_sizes[INDEX_AC].cs_cachep 三链,原本指向静态变量 initkmem_list3。
  5. 更新初始化进度


静态初始化的结构比如:

/* internal cache of cache description objs *///这就是静态定义了第一个即通用缓存器static struct kmem_cache cache_cache = {    .batchcount = 1,    .limit = BOOT_CPUCACHE_ENTRIES,    .shared = 1,    .buffer_size = sizeof(struct kmem_cache),    .name = "kmem_cache",  //卧槽,名字就叫 kmem_cache};

或者

static struct arraycache_init initarray_cache /*__initdata*/ =    { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };static struct arraycache_init initarray_generic =    { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} };


该函数其他辅助函数有:
1. 三链初始化函数

static void kmem_list3_init(struct kmem_list3 *parent){    INIT_LIST_HEAD(&parent->slabs_full);    INIT_LIST_HEAD(&parent->slabs_partial);    INIT_LIST_HEAD(&parent->slabs_free);    parent->shared = NULL;    parent->alien = NULL;    parent->colour_next = 0;    spin_lock_init(&parent->list_lock);    parent->free_objects = 0;    parent->free_touched = 0;}

这个没什么卵用,就只是初始化。

2. 对齐宏

#define ALIGN(x,a)      __ALIGN_MASK(x,(typeof(x))(a)-1)#define __ALIGN_MASK(x,mask)    (((x)+(mask))&~(mask))

这个宏用来控制内存以 a 的大小为基本单位对齐,0~7为一组,以此类推。

关于这个宏详细解释可参照:内核宏ALIGN的含义

3. cache_estimate()函数
这个函数用来计算每个 slab 中对象的数目以及浪费空间的大小,注释中的管理对象就是前面所说的管理者。

/* * Calculate the number of objects and left-over bytes for a given buffer size. */static void cache_estimate(unsigned long gfporder, size_t buffer_size,               size_t align, int flags, size_t *left_over,               unsigned int *num){    int nr_objs;    size_t mgmt_size;    //slab 大小为 2^gfporder 个页面    size_t slab_size = PAGE_SIZE << gfporder;  //#define PAGE_SIZE 0x400 (即1024),FIXME: 难道一个页面是 1K ,怎么可能?    /*     * The slab management structure can be either off the slab or  //有off-slab和on-slab两种方式     * on it. For the latter case, the memory allocated for a     * slab is used for:   //这段内存被用来存储:     *     * - The struct slab      //slab结构体     * - One kmem_bufctl_t for each object    //每个对象的kmem_bufctl_t     * - Padding to respect alignment of @align  //对齐的大小     * - @buffer_size bytes for each object   //每个对象的大小     *     * If the slab management structure is off the slab, then the     * alignment will already be calculated into the size. Because   //如果是off-slab,align早已被计算出来     * the slabs are all pages aligned, the objects will be at the   //因为所有的页面对齐过了,对象申请时会处在正确的位置     * correct alignment when allocated.     */     //对于外置slab,没有slab管理对象问题,直接用申请空间除以对象大小就是对象个数    if (flags & CFLGS_OFF_SLAB) {        //外置slab不存在管理对象,全部用于存储slab对象        mgmt_size = 0;        //所以对象个数 = slab大小 / 对象大小        nr_objs = slab_size / buffer_size;    //注意buffer_size已经和cache line对齐过了        //对象个数不许超限        if (nr_objs > SLAB_LIMIT)            nr_objs = SLAB_LIMIT;    } else {        /*         * Ignore padding for the initial guess. The padding         * is at most @align-1 bytes, and @buffer_size is at         * least @align. In the worst case, this result will         * be one greater than the number of objects that fit         * into the memory allocation when taking the padding         * into account.         */         //内置式slab,slab管理对象与slab对象都在一片内存中,此时slab页面包含:         //一个struct slab 对象,一个kmem_bufctl_t 类型数组(kmem_bufctl_t 数组的项数和slab对象数目相同)        //slab大小需要减去管理对象大小,所以对象个数为 剩余大小 / (每个对象大小 + sizeof(kmem_bufctl_t)), 它们是一一匹配的关系        nr_objs = (slab_size - sizeof(struct slab)) /              (buffer_size + sizeof(kmem_bufctl_t));        /*         * This calculated number will be either the right         * amount, or one greater than what we want.         */         //如果对齐后超过slab 总大小 ,需要减去一个对象        if (slab_mgmt_size(nr_objs, align) + nr_objs*buffer_size               > slab_size)            nr_objs--;        //对象个数不许超限        if (nr_objs > SLAB_LIMIT)            nr_objs = SLAB_LIMIT;        //计算  管理对象以缓存行  对齐后的总大小        mgmt_size = slab_mgmt_size(nr_objs, align);    }    //得出slab最终对象个数    *num = nr_objs;    //前面已经得到了slab管理对象大小(外置为0,内置也已计算),这样就可以最终的出slab最终浪费空间大小    *left_over = slab_size - nr_objs*buffer_size - mgmt_size;}


5. malloc_sizes[]表
我们的需要通过 kmem_cache_create() 函数创建通用缓存器,最终实际会向伙伴系统申请。那创建多大呢?这个有一个很有意思的地方:
首先看 INDEX_AC:

#define INDEX_AC index_of(sizeof(struct arraycache_init))

而 index_of 是这样的:

/* * This function must be completely optimized away if a constant is passed to * it.  Mostly the same as what is in linux/slab.h except it returns an index. */static __always_inline int index_of(const size_t size) //这个函数用来选择大小的,可作为mallloc_size的参数  {    extern void __bad_size(void);    if (__builtin_constant_p(size)) {        int i = 0;#define CACHE(x) \    if (size <=x) \     //适配一个刚足够容纳size的大小        return i; \    else \        i++;   //不成功,增大继续适配#include "linux/kmalloc_sizes.h"#undef CACHE        __bad_size();    } else        __bad_size();    return 0;}   

为什么说 index_of 能确定大小呢,这真是有点玄幻了。注意这一句

#include "linux/kmalloc_sizes.h"

而 linux/kmalloc_sizes.h 中的内容是这样的:

#if (PAGE_SIZE == 4096)    CACHE(32)#endif    CACHE(64)#if L1_CACHE_BYTES < 64    CACHE(96)#endif    CACHE(128)#if L1_CACHE_BYTES < 128    CACHE(192)#endif    CACHE(256)    CACHE(512)    CACHE(1024)    CACHE(2048)    CACHE(4096)    CACHE(8192)    CACHE(16384)    CACHE(32768)    CACHE(65536)    CACHE(131072)#if KMALLOC_MAX_SIZE >= 262144    CACHE(262144)#endif#if KMALLOC_MAX_SIZE >= 524288    CACHE(524288)#endif#if KMALLOC_MAX_SIZE >= 1048576    CACHE(1048576)#endif#if KMALLOC_MAX_SIZE >= 2097152    CACHE(2097152)#endif#if KMALLOC_MAX_SIZE >= 4194304    CACHE(4194304)#endif#if KMALLOC_MAX_SIZE >= 8388608    CACHE(8388608)#endif#if KMALLOC_MAX_SIZE >= 16777216    CACHE(16777216)#endif#if KMALLOC_MAX_SIZE >= 33554432    CACHE(33554432)#endif

在 index_of 函数中局部定义了 CACHE(x) 宏,并把这个头文件引入,你可以理解为把头文件中所有的内容都加入到了 index_of 函数的那一句所在的位置。那么,程序接下来会不停地执行者个局部宏 CACHE(X),而这个宏又是有函数意义的,当匹配到正确的正确的size,会直接返回 i 值(真是神一样的技巧,相当于用宏来循环,我算是服了)。通过这种方式就确定了要申请的大小对应在 malloc_sizes 表中下标 i 的值。

那么只知道下标 i 的值可不行,malloc_sizes[]表是什么时候初始化的呢? 答案是它是静态初始化的。

/* * These are the default caches for kmalloc. Custom caches can have other sizes. */struct cache_sizes malloc_sizes[] = {  //通用缓存器的大小由malloc_size表决定#define CACHE(x) { .cs_size = (x) },#include <linux/kmalloc_sizes.h>   //终于明白这是什么用法了    CACHE(ULONG_MAX)#undef CACHE};

在上面的代码中,同样定义了 CACHE(X),不过这个可和之前的那个作用不一样,它们俩都是局部宏,使用完即 undef,不会产生影响。

在这里注意,这个宏被定义为 “{ .cs_size = (x) },”,注意到这个逗号了没有?下面会同样引入 kmalloc_size 头文件中的一大堆 CACHE(x),每个都是这种形式,这不正是数组的初始化方式吗?只不过每个数据类型都是 cache_sizes 类型罢了。相当于int array[] = { {1}, {2}, …},大概就是这样。cache_names[] 表同理。

cache_sizes 类型如下:

/* Size description struct for general caches. */struct cache_sizes {    size_t          cs_size;    //通用缓存器的大小    struct kmem_cache   *cs_cachep;   //通用缓存器的描述符指针#ifdef CONFIG_ZONE_DMA    struct kmem_cache   *cs_dmacachep;#endif};

于是,通过上面这种初始化方式,就把 malloc_sizes[] 表中按照由小到大顺序将全部 cache_sizes的 cs_size 成员初始化了。所以 malloc_size[i] 对应的就是描述大小为 i 的缓存器的 cache_sizes 结构,通过 .cs_cachep 就可以得到对应大小的通用缓存器!

如果是 DMA,那么会配置两种通用缓存器。

6. kmem_cache_create()函数
这个函数是核心,对该函数的详细分析会在下一篇博客出现,很长的:)

7. kmalloc()函数
也是重点,以后会单独剖析。

8. init_list()函数

/* * swap the static kmem_list3 with kmalloced memory */static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list,            int nodeid){    struct kmem_list3 *ptr;    ptr = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, nodeid);    BUG_ON(!ptr);    local_irq_disable();    memcpy(ptr, list, sizeof(struct kmem_list3));    /*     * Do not assume that spinlocks can be initialized via memcpy:     */    spin_lock_init(&ptr->list_lock);    MAKE_ALL_LISTS(cachep, ptr, nodeid);    cachep->nodelists[nodeid] = ptr;    local_irq_enable();}

这是利用 kmalloc 申请三链和静态三链交换的函数,为什么说是利用 kmalloc 呢,且看它调用的 kmalloc_node() 函数:

static inline void *kmalloc_node(size_t size, gfp_t flags, int node){    return kmalloc(size, flags);}   

就是这样,我们为了解决“鸡与蛋”的问题,首先设定几个静态变量,比如三链 initkmem_list3,先用它合成我们的 cache_cache,然后有了 cache_cache,这是为缓存器制定规则的缓存器,通过它我们就可以随意合成大小其他缓存器了。有了各种大小的缓存器,在 kmem_cache_init() 函数后半部分就可以用缓存器来 kmalloc 分配对象,替换之前所有用来辅助 cache_cache 的静态数据结构(如 initarray_cache, initkmem_list3),以后这些静态数据结构就不再使用了。

cache_cache 为缓存器大小制定了一种规则,这说明所有缓存器自身大小也是一样的,只不过它们的 buffer_size 字段描述的用来分配的对象大小是不一样的,以后不同大小的对象就靠这个找不同的缓存器分配就行了。


参考:

  • kmem_cache_init初始化文字解析
  • Linux Slab分配器(一)–概述


PS: 最近是怎么了,有点慌,觉得学了几天才学了这么一点东西,感觉好没有成就感。嗯,没慌,搞技术的要静的下心来。

0 0
原创粉丝点击