[置顶] linux 3.4.10 内核内存管理源代码分析6:Slab分配器

时间:2021-05-07 23:40:14

 法律声明linux 3.4.10 内核内存管理源代码分析》系列文章由机器人ancjf@163.com)发表于http://blog.csdn.net/ancjf,文章遵循GPL协议。欢迎转载,转载请注明作者和此条款。

Slab分配器

         伙伴系统一次内存分配最少都是一页,实际上很多时候我们分配内存的时候都只是一小块,不需要一页这样大的空间。这时候我们可以从slab来分配内存,Slab是伙伴系统之上的一个内存分配器,设计slab的目的是避免伙伴系统的一些缺陷。

        

内存分配的实质就是根据申请者申请的参数查找一块合适的内存,然后把内存地址返回。伙伴系统是最底层的内存管理系统,Slab是在伙伴系统之上的一个内存分配器,slab把从伙伴系统申请的内存块分割成更小的块来管理,分配的时候查找一个合适的块返回首地址。

slab从伙伴系统申请的内存块用struct slab描述,但Slab并不是直接基于struct slab来管理内存,因为还有几个需要考虑的因素:

一:在多cpu环境下,访问一个变量需要获得回环锁,如果对每个cpu缓存一些内存空间,这样可以提高性能。Slab采取的方法是对每个cpu缓存一些对象,如果cpu缓存的对象为空了则一次从获取一批对象缓存起来。为了这个因素,定义了结构struct array_cache。

二:在numa系统上,每个节点上的访问速度可能不一样,分配时候需要选择合适节点来进行分配,对slab块也应该能按节点管理。针对这个因素定义了结构structkmem_list3。

三:能同时对多个slab块进行管理,可以提高程序灵活性。在structkmem_list3中设定了三个链表分别是块,闲,和半空slab块链表。

处于slab顶层的是slab缓存,slab缓存用struct kmem_cache描述。上面的结构都在struct kmem_cache中组织起来。每次内存分配都是在一个slab缓存中进行的,一个slab缓存中分配的对象的长度都是相同的。

下面是这些结构的定义:

struct slab定义如下:

struct slab {

         union {

                   struct {

                            struct list_headlist;         //一个缓存中的所有slab块组成的链表

                            unsigned longcolouroff;           //着色区的大小

                            void *s_mem;           //指向对象区的起点

                            unsigned int inuse;  //Slab中所分配对象的个数

                            kmem_bufctl_t free;        //指向空闲对象链中的第一个对象

                            unsigned shortnodeid;    //slab块所在结点的结点号

                   };

                   struct slab_rcu__slab_cover_slab_rcu;

         };

};

 

structarray_cache定义如下:

structarray_cache {

         unsigned int avail;             //当前缓存的对象数目

         unsigned int limit;             //最多可以缓存的对象数目

         unsigned int batchcount;         //缓存对象空的情况下一次获取的对象数

         unsigned int touched;      //用来表示这个对象最新是否被使用

         spinlock_t lock;         //回环锁

         void *entry[];            //指向缓存对象数组

};

 

structkmem_list3定义如下:

structkmem_list3 {

         struct list_head slabs_partial;                  //分配空的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;        //下一个颜色

         spinlock_t list_lock;

         struct array_cache *shared;   //共享的对象缓存

         struct array_cache **alien;    /* on other nodes */

         unsigned long next_reap;        //定义了内核在两次尝试收缩缓存之间,必须经过的时间间隔

         int free_touched;              //表示三链表是否是活动的

};

 

structkmem_cache定义如下:

structkmem_cache {

/* 1) Cachetunables. Protected by cache_chain_mutex */

         unsigned int batchcount;         //一批对象的数量

         unsigned int limit;             //空闲对象数上限

         unsigned int shared;        //共享对象数

 

         unsigned int buffer_size;                   //对象实际长度

         u32 reciprocal_buffer_size;     //

/* 2) touched byevery alloc & free from the backend */

 

         unsigned int flags;            //一些固定的标志位

         unsigned int num;             //每个slab块包含的对象数

 

/* 3)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;                     //颜色数

         unsigned int colour_off;           //色差,相邻两种颜色的便宜值的差

         struct kmem_cache *slabp_cache;                   //如果slab块的管理数据是独立的,则在这个缓存中分配空间

         unsigned int slab_size;            

         unsigned int dflags;          /* dynamic flags */

 

         /* constructor func */

         void (*ctor)(void *obj);              //构造函数

 

/* 4) cachecreation/removal */

         const char *name;            //缓存名称,在整个系统中是唯一的

         struct list_head next;      //所有的slab缓存用这个结果连接成一个链表

 

/* 5) statistics*/

#ifdefCONFIG_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 allocatorcan 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 userobject and its size.

          */

         int obj_offset;

         int obj_size;

#endif /*CONFIG_DEBUG_SLAB */

 

/* 6)per-cpu/per-node data, touched during every alloc/free */

         /*

          * We put array[] at the end of kmem_cache,because we want to size

          * this array to nr_cpu_ids slots instead ofNR_CPUS

          * (see kmem_cache_init())

          * We still use [NR_CPUS] and not [1] or [0]because cache_cache

          * is statically defined, so we reserve the maxnumber of cpus.

          */

         struct kmem_list3 **nodelists;                //指向三链表数组

         struct array_cache *array[NR_CPUS];    //对每个cpu,指向每个cpu的对象缓存

         /*

          * Do not add fields after array[]

          */

};

 

对象:一块内存空间,用空间的首地址标识。

三链表:对应struct kmem_list3,包含空,满,部分空三个链表。

对象缓存;缓存堆栈:对应struct array_cache,用来缓存一些对象。

缓存;slab缓存:对应struct kmem_cache。