1. 程式人生 > >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 tonext free item at end of page, or0*/
    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數.

有點倉促,以後再完善~~