早就據說過Memcached獨特的內存管理方式,寫着篇文章的目的就是了解Memcached的內存管理,學習其源代碼.數組
memcached默認狀況下采用了名爲Slab Allocator的機制分配、管理內存,Slab Allocator的基本原理是按照預先規定的大小,將分配的內存分割成特定長度的塊,以指望徹底解決內存碎片問題。並且,slab allocator還有重複使用已分配的內存的目的。 也就是說,分配到的內存不會釋放,而是重複利用。緩存
Page 分配給Slab的內存空間,默認是1MB,分配給Slab以後根據slab的大小切分紅chunk Chunk 用於緩存記錄的內存空間 Slab Class 特定大小的chunk的組
在Memcached啓動時候會調用slab的初始化代碼(詳見memcached.c中main函數調用slabs_init函數).memcached
slabs_init函數聲明:函數
1
2 3 4 5 6 7 |
/** Init the subsystem. 1st argument is the limit on no. of bytes to allocate, 0 if no limit. 2nd argument is the growth factor; each slab will use a chunk size equal to the previous slab's chunk size times this factor. 3rd argument specifies if the slab allocator should allocate all memory up front (if true), or allocate memory in chunks as it is needed (if false) */ void slabs_init(const size_t limit, const double factor, const bool prealloc); |
其中limit表示memcached最大使用內存;factor表示slab中chunk size的增加因子,slab中chunk size的大小等於前一個slab的chunk size乘以factor;學習
memcached.c中main函數調用slabs_init函數:ui
1
|
slabs_init(settings.maxbytes, settings.factor, preallocate); |
其中settings.maxbytes默認值爲64M,啓動memcached使用選項-m設置;settings.factor默認爲1.25,啓動memcached時候使用-f設置;preallocate指的是啓動memcached的時候默認爲每種類型slab預先分配一個page的內存,默認是false;this
1
2 3 4 5 |
settings.maxbytes = 64 * 1024 * 1024; /* default is 64MB */ ... settings.factor = 1.25; ... preallocate = false |
slabs_init函數實現:spa
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
/** * Determines the chunk sizes and initializes the slab class descriptors * accordingly. */ void slabs_init(const size_t limit, const double factor, const bool prealloc) { int i = POWER_SMALLEST - 1; //真實佔用大小=對象大小+48 unsigned int size = sizeof(item) + settings.chunk_size; mem_limit = limit; //開啓預分配,則首先將limit大小(默認64M)的內存所有申請 if (prealloc) { /* Allocate everything in a big chunk with malloc */ mem_base = malloc(mem_limit); if (mem_base != NULL) { mem_current = mem_base; mem_avail = mem_limit; } else { fprintf(stderr, "Warning: Failed to allocate requested memory in" " one large chunk.\nWill allocate in smaller chunks\n"); } } //清空全部的slab memset(slabclass, 0, sizeof(slabclass)); while (++i < POWER_LARGEST && size <= settings.item_size_max / factor) { /* Make sure items are always n-byte aligned */ if (size % CHUNK_ALIGN_BYTES) size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES); slabclass[i].size = size; slabclass[i].perslab = settings.item_size_max / slabclass[i].size; size *= factor; if (settings.verbose > 1) { fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n", i, slabclass[i].size, slabclass[i].perslab); } } //最大chunksize的一個slab,chunksize爲settings.item_size_max(默認1M) power_largest = i; slabclass[ |