本文基于memcached 1.2.0写成php
memcached的内存分配器slab.c不过300行代码,仍是比较容易上手分析的。git
内存模型以下: github
函数名 | 做用 |
---|---|
slabs_init | 初始化slabclass_t结构体数组 |
slabs_clsid | 经过内存大小从slabclass_t数组中找到最小能知足的结构体 |
slabs_preallocate | 给每一个slabclass_t先分配一个slab(页)的内存(1mb) |
slabs_newslab | 给指定的slabclass分配一个新的slab存放到slab_list上,同时slabs、end_page_ptr、end_page_free发生相应变化 |
grow_slab_list | 动态增长slab_list数组的大小 |
slabs_alloc | 从内存分配器中取出一个空的item内存来使用 |
slabs_free | 将item所在的内存指针从新标记成可以使用,至关于删除了item |
slabs_stats | 从slabclass_t结构体上获取内存分配器的使用状况 |
其中被slab.c之外的文件调用的函数有slabs_alloc、slabs_free、slabs_init和slabs_stats数组
unsigned int size = sizeof(item) + settings.chunk_size;
复制代码
这里有一个分支,若是当前slabclass的当前slab还有剩余的内存空间,直接就分配了,参考:memcached
if (! (p->end_page_ptr || p->sl_curr || slabs_newslab(id)))
return 0;
复制代码
三种状况函数
/* return off our freelist, if we have one */
if (p->sl_curr)
return p->slots[--p->sl_curr];
/* if we recently allocated a whole page, return from that */
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;
}
复制代码
主要就是把删除的item放进slabclass_t的slots数组中,申请内存时,优先从这个slots中获取,达到这个memcached解决内存碎片的目的ui
这里有个对这个存放被删除的item的slots数组扩容的操做spa
if (p->sl_curr == p->sl_total) { /* need more space on the free list */
int new_size = p->sl_total ? p->sl_total*2 : 16; /* 16 is arbitrary */
void **new_slots = realloc(p->slots, new_size*sizeof(void *));
if (new_slots == 0)
return;
p->slots = new_slots;
p->sl_total = new_size;
}
复制代码
能够看到这个slots数组初始容量是16,后续每都是按照2倍容量进行扩容的.net
memcached的源代码命名不规范,可能在阅读源码上形成极大的干扰3d
注释不清楚具备迷惑性
memcached使用注意事项
持续更新中...