首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

memcached slabs内存储器分配算法详解

2012-09-24 
memcached slabs内存分配算法详解[liexusong原创]Memcached Slab算法是根据powers of 2来将1MB的内存块划

memcached slabs内存分配算法详解

[liexusong原创]

Memcached Slab算法是根据powers of 2来将1MB的内存块划分成多个小内存块,?而这1MB的内存块称为页:

?

Powers of 2是2的n次方的意思,例如:2的0次方是1,2的1次方是2,2的2次方是4,2的3次方是8等等。

而将1MB的内存按2的n次方划分可以划分成20种不同的内存块,因为2的20次方是1MB(1048576)。所以可以说,memcached管理着20种不同的内存块的集合。

memcached slabs内存储器分配算法详解

而memcached是通过slabclass_t结构体来管理这些小内存块的, slabclass_t的定义如下:

typedef struct?{

????unsigned int?size;?????

????unsigned int?perslab;??

?

????void?**slots;??????????

????unsigned int?sl_total;?

????unsigned int?sl_curr;??

?

????void?*end_page_ptr;

????unsigned int?end_page_free;

?

????unsigned int?slabs;????

?

????void?**slab_list;??????

????unsigned int?list_size;

?

????unsigned int?killing;?

}?slabclass_t;

?

(1)???slots指针指向的是内存分配器回收的小内存块的数组, sl_total保存了回收器的容量,?当回收器容量不足时,?需要重新分配更大的内存来作为回收器, sl_curr是当前回收器回收到的位置,?下一个回收的内存块就会放到这里:


memcached slabs内存储器分配算法详解

(2)???end_page_ptr保存的是当前的空闲内存块, end_page_free保存的是当前空闲块的数量,?如果end_page_free等于0表示已经没有空闲内存块了,?需要向系统申请一块新的内存页.

memcached slabs内存储器分配算法详解


(3)???slab_list保存的是申请的内存页, slabs保存的是已经申请的内存页数量.?memcached slabs内存储器分配算法详解

所以综合起来的总体结构图:


memcached slabs内存储器分配算法详解

slab分配函数(slabs_alloc):

if?(! (p->end_page_ptr?|| p->sl_curr || slabs_newslab(id)))

????return?0;

?

?

?

if?(p->sl_curr)

????return?p->slots[--p->sl_curr];

?

?

if?(p->end_page_ptr) {

????void?*ptr = p->end_page_ptr;

????if?(--p->end_page_free) {

????????p->end_page_ptr += p->size;

????}?else?{

????????p->end_page_ptr = 0;

????}

????return?ptr;

}

?

函数中首先判断是否有空闲内存块,?或者回收过的内存块,?如果都没有就调用slabs_newslab()新建一个内存页;?然后优先分配回收过的内存块,?如果没有才去分配空闲的内存块.

?

slabs_newslab()函数是新建一个内存页.

int?slabs_newslab(unsigned?int?id) {

????slabclass_t?*p = &slabclass[id];

????int?num = p->perslab;

????int?len = POWER_BLOCK;

????char?*ptr;

?

????if?(mem_limit && mem_malloced?+ len > mem_limit)

????????return?0;

?

????if?(! grow_slab_list(id))?return?0;

??

????ptr =?malloc(len);

????if?(ptr == 0)?return?0;

?

????memset(ptr, 0, len);

????p->end_page_ptr?= ptr;

????p->end_page_free?= num;

?

????p->slab_list[p->slabs++] = ptr;

????mem_malloced?+= len;

????return?1;

}

?

slabs_newslab()每次分配1MB作为内存页.?然后把end_page_ptr指向这个新的内存页.

?

?

slab回收函数(slabs_free):

void?slabs_free(void?*ptr,?unsigned?int?size) {

????unsigned?char?id = slabs_clsid(size);

????slabclass_t?*p;

?

????if?(id < POWER_SMALLEST?|| id > POWER_LARGEST)

????????return;

?

????p = &slabclass[id];

????if?(p->sl_curr == p->sl_total) {

????????int?new_size = p->sl_total ? p->sl_total*2 : 16;?

????????void?**new_slots =?realloc(p->slots, new_size*sizeof(void?*));

????????if?(new_slots == 0)

????????????return;

????????p->slots = new_slots;

????????p->sl_total = new_size;

????}

????p->slots[p->sl_curr++] = ptr;

????return;

}

?

回收时,?直接用回收器(slots)的指针指向这个内存块,?这样就完成回收操作.?如果回收器不够大,?就扩充回收器.


热点排行