本文基於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使用注意事項
持續更新中...