memcache内存池的设计原理

memcache内存池的设计原理

memcache中管理内存的数据结构如下:

typedef struct {
    unsigned 
int  size;       /*  sizes of items  */
    unsigned 
int  perslab;    /*  how many items per slab  */

    void 
** slots;            /*  list of item ptrs  */
    unsigned 
int  sl_total;   /*  size of previous  array   */
    unsigned 
int  sl_curr;    /*  first free slot  */

    void 
* end_page_ptr;          /*  pointer  to   next  free item at  end  of page,  or   0   */
    unsigned 
int  end_page_free;  /*  number of items remaining at  end  of last alloced page  */

    unsigned 
int  slabs;      /*  how many slabs were allocated  for  this class  */

    void 
** slab_list;        /*   array  of slab pointers  */
    unsigned 
int  list_size;  /*  size of prev  array   */

    unsigned 
int  killing;   /*  index + 1  of dying slab,  or  zero  if  none  */
} slabclass_t;

程序中有一个全局的数组
static slabclass_t slabclass[POWER_LARGEST + 1]用于保存slab,预分配内存池时调用的是void slabs_init(const size_t limit, const double factor) 函数,其中limit是内存池的最大容量,factor是分配时的增长因子.
比方说,加入factor是2,第一个在slabclass数组中的slab的每个item大小是128字节,那么下一个slab每个item的大小就是128*2,再下一个就是128*2*2(注意,为了简化问题的说明,上面没有考虑地址对齐的因素).

在预分配内存池时,最多给每个slab保存item的容量是1M内存,这个数值由#define POWER_BLOCK 1048576决定.
因此,slab中的几个元素在预分配内存时是这么定的:
size有一个起始值,这个值以后的增长由factor决定,增长的过程前面已经阐述过了;
perslab保存的是一个slab存放的item数量,因此perslab = POWER_BLOCK / slabclass[i].size;
如果预先分配一段内存供使用的话,也就是没有定义DONT_PREALLOC_SLABS宏,那么就调用slabs_preallocate进行预分配内存.
其中,end_page_ptr指向这个预分配好的指针,end_page_free表示的是目前空闲可用item的数量,在预分配时,这个值与perslab相同.
在这个内存池模型中,每个page实际上是一个数组,数组中每个元素的大小就是这个slab中item的大小.

另外,slots保存的是释放出来的item指针,sl_total表示总的数量,sl_curr表示的是目前可用的已经释放出来的item数量.

每一次要分配内存的时候,首先根据需要分配的内存大小在slabclass数组中查找索引最小的一个大于所要求内存的slab,如果slots不为空,那么就从这里返回内存,否则去查找end_page_ptr,如果也没有,那么就只能返回NULL了.
每一次释放内存的时候,同样的找到应该返回内存的slab元素,改写前面提到的slot指针和sl_curr数.

有点仓促,以后再完善~~


你可能感兴趣的:(memcache内存池的设计原理)