转载请注明出处:http://blog.youkuaiyun.com/luotuo44/article/details/42737181
温馨提示:本文用到了一些可以在启动memcached设置的全局变量。关于这些全局变量的含义可以参考《memcached启动参数详解》。对于这些全局变量,处理方式就像《如何阅读memcached源代码》所说的那样直接取其默认值。
slab内存池分配
slab简介:
memcached使用了一个叫slab的内存分配方法,有关slab的介绍可以参考链接1和链接2。可以简单地把它看作内存池。memcached内存池分配的内存块大小是固定的。虽然是固定大小,但memcached的能分配的内存大小(尺寸)也是有很多种规格的。一般来说,是满足需求的。
memcached声明了一个slabclass_t结构体类型,并且定义了一个slabclass_t类型数组slabclass(是一个全局变量)。可以把数组的每一个元素称为一个slab分配器。一个slab分配器能分配的内存大小是固定的,不同的slab分配的内存大小是不同的。下面借一幅经典的图来说明:
从每个slab class(slab分配器)分配出去的内存块都会用指针连接起来的(连起来才不会丢失啊)。如下图所示:
上图是一个逻辑图。每一个item都不大,从几B到1M。如果每一个item都是地动态调用malloc申请的,势必会造成很多内存碎片。所以memcached的做法是,先申请一个比较大的一块内存,然后把这块内存划分成一个个的item,并用两个指针(prev和next)把这些item连接起来。所以实际的物理图如下所示:
上图中,每一个slabclass_t都有一个slab数组。同一个slabclass_t的多个slab分配的内存大小是相同的,不同的slabclass_t分配的内存大小是不同的。因为每一个slab分配器能分配出去的总内存都是有一个上限的,所以对于一个slabclass_t来说,要想分配很多内存就必须有多个slab分配器。
确定slab分配器的分配规格:
看完了图,现在来看一下memcached是怎么确定slab分配器的分配规格的。因为memcached使用了全局变量,先来看一下全局变量。
[cpp] view plain copy
在CODE上查看代码片派生到我的代码片
//slabs.c文件
typedef struct {
unsigned int size;//slab分配器分配的item的大小
unsigned int perslab; //每一个slab分配器能分配多少个item
void *slots; //指向空闲item链表
unsigned int sl_curr; //空闲item的个数
//这个是已经分配了内存的slabs个数。list_size是这个slabs数组(slab_list)的大小
unsigned int slabs; //本slabclass_t可用的slab分配器个数
//slab数组,数组的每一个元素就是一个slab分配器,这些分配器都分配相同尺寸的内存
void **slab_list;
unsigned int list_size; //slab数组的大小, list_size >= slabs
//用于reassign,指明slabclass_t中的哪个块内存要被其他slabclass_t使用
unsigned int killing;
size_t requested; //本slabclass_t分配出去的字节数
} slabclass_t;
#define POWER_SMALLEST 1
#define POWER_LARGEST 200
#define CHUNK_ALIGN_BYTES 8
#define MAX_NUMBER_OF_SLAB_CLASSES (POWER_LARGEST + 1)
//数组元素虽然有MAX_NUMBER_OF_SLAB_CLASSES个,但实际上并不是全部都使用的。
//实际使用的元素个数由power_largest指明
static slabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES];//201
static int power_largest;//slabclass数组中,已经使用了的元素个数.
可以看到,上面的代码定义了一个全局slabclass数组。这个数组就是前面那些图的slabclass_t数组。虽然slabclass数组有201个元素,但可能并不会所有元素都使用的。由全局变量power_largest指明使用了多少个元素.下面看一下slabs_init函数,该函数对这个数组进行一些初始化操作。该函数会在main函数中被调用。
[cpp] view plain copy
在CODE上查看代码片派生到我的代码片
//slabs.c文件
static size_t mem_limit = 0;//用户设置的内存最大限制
static size_t mem_malloced = 0;
//如果程序要求预先分配内存,而不是到了需要的时候才