日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

Memcached内存池分析

發(fā)布時(shí)間:2023/11/27 生活经验 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Memcached内存池分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

針對(duì)Memcacged1.4.15代碼

1.完整slabs內(nèi)存池圖

這是我畫(huà)的memcached的slabs內(nèi)存池對(duì)象關(guān)系圖:


2.內(nèi)存池?cái)?shù)據(jù)結(jié)構(gòu)

typedef struct {unsigned int size;????? /* 每個(gè)item的大小 */unsigned int perslab;?? /* 每個(gè)page中包含多少個(gè)item */void *slots;?????????? //空閑的item列表,指向最后一個(gè)空閑的chunk的地址,如果perslab=1那么slots和slab_list[0]指向的地址是同一個(gè)unsigned int sl_curr;?? //當(dāng)前空閑的item位置(也就是實(shí)際空閑item個(gè)數(shù)),從后往前的unsigned int slabs;???? //已分配chunk數(shù)目void **slab_list;?????? //所有的page指針,指向page的地址,也是第一個(gè)chunk的地址,可以用(item *)((&slabclass[N])->slab_list[0])獲取第一個(gè)itemunsigned int list_size; //每個(gè)數(shù)組trunk數(shù)目,默認(rèn)是16unsigned int killing;? /* index+1 of dying slab, or zero if none */size_t requested; //已分配總內(nèi)存大小
} slabclass_t;//slots:指向free chunk塊的指針數(shù)組,slots的指針指向一個(gè)void //*的數(shù)組,該數(shù)組中的每一個(gè)元素的內(nèi)容均指向一個(gè)空閑的chunk塊,而且相同slabclass上的所有slab中的free chunk塊均掛接到這個(gè)鏈表上;
//slabs:當(dāng)前slabclass中分配的頁(yè)內(nèi)存?zhèn)€數(shù);
//slab_list:當(dāng)前slabclass所分配的頁(yè)內(nèi)存(slab)的指針數(shù)組,每一個(gè)數(shù)組元素的內(nèi)容均是一個(gè)指向頁(yè)內(nèi)存地址的指針;
//        size_t new_size =  (p->list_size != 0) ? p->list_size * 2 : 16;
//        void *new_list = realloc(p->slab_list, new_size * sizeof(void *));
//        if (new_list == 0) return 0;
//        p->list_size = new_size;
//        p->slab_list = new_list;static slabclass_t slabclass[MAX_NUMBER_OF_SLAB_CLASSES];
static size_t mem_limit = 0;//內(nèi)存限制大小,如果默認(rèn)64M?? slabs_init的時(shí)候
static size_t mem_malloced = 0;//已分配大小
static int power_largest;//數(shù)組最大個(gè)數(shù),默認(rèn)是42static void *mem_base = NULL;
static void *mem_current = NULL;//內(nèi)存使用當(dāng)前地址
static size_t mem_avail = 0;//剩余內(nèi)存/*** slab 線程鎖*/
static pthread_mutex_t slabs_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t slabs_rebalance_lock = PTHREAD_MUTEX_INITIALIZER;

3.初始化slabs_init

/* slab初始化*/
/* limit:內(nèi)存大小(字節(jié));factor:增長(zhǎng)因子;prealloc:是否一次性分配內(nèi)存*/
void slabs_init(const size_t limit, const double factor, const bool prealloc) {int i = POWER_SMALLEST - 1;//0unsigned int size = sizeof(item) + settings.chunk_size;//chunk_size 最小分配空間mem_limit = limit;//內(nèi)存限制大小if (prealloc) {//一次分配所有設(shè)置的內(nèi)存/* 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");}}memset(slabclass, 0, sizeof(slabclass));
//settings.item_size_max = 1024 * 1024=1M; /* The famous 1MB upper limit. */
//settings.item_size_max / factor??? 1048576/1.25=838860.8 這就是單page最大的chunk大小 字節(jié)
//slabclass[41]?? ?{size=717184 perslab=1 slots=0x00000000 ...}?? ?slabclass_t
//所以到了42就跳出循環(huán)了
//slabclass[42]?? ?{size=1048576 perslab=1 slots=0x00000000 ...}?? ?slabclass_t
//43就不分配了
//slabclass[43]?? ?{size=0 perslab=0 slots=0x00000000 ...}?? ?slabclass_twhile (++i < POWER_LARGEST && size <= settings.item_size_max / factor) {/* Make sure items are always n-byte aligned */if (size % CHUNK_ALIGN_BYTES)//字節(jié)數(shù)為8的倍數(shù)size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);slabclass[i].size = size;//item大小slabclass[i].perslab = settings.item_size_max / slabclass[i].size;//item數(shù)目size *= factor;//乘以增長(zhǎng)因子if (settings.verbose > 1) {fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",i, slabclass[i].size, slabclass[i].perslab);}}power_largest = i;//默認(rèn)=42slabclass[power_largest].size = settings.item_size_max;slabclass[power_largest].perslab = 1;//最大的只能存儲(chǔ)一個(gè)itemif (settings.verbose > 1) {fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",i, slabclass[i].size, slabclass[i].perslab);}/* for the test suite:? faking of how much we've already malloc'd */{char *t_initial_malloc = getenv("T_MEMD_INITIAL_MALLOC");if (t_initial_malloc) {mem_malloced = (size_t)atol(t_initial_malloc);}}#ifndef DONT_PREALLOC_SLABS{char *pre_alloc = getenv("T_MEMD_SLABS_ALLOC");if (pre_alloc == NULL || atoi(pre_alloc) != 0) {slabs_preallocate(power_largest);}}
#endif
}

4.第一次分配slab

最初是在do_item_alloc中調(diào)用do_slabs_alloc

#0? do_item_alloc (key=0x7ffff0013754 "key", nkey=3, flags=0, exptime=0, nbytes=5, cur_hv=0) at items.c:190
#1? 0x0000000000415706 in item_alloc (key=0x7ffff0013754 "key", nkey=3, flags=0, exptime=0, nbytes=5) at thread.c:486
#2? 0x000000000040a38e in process_update_command (c=0x7ffff0013550, tokens=0x7ffff7ae4b00, ntokens=6, comm=2, handle_cas=false) at memcached.c:2917
#3? 0x000000000040b43d in process_command (c=0x7ffff0013550, command=0x7ffff0013750 "set") at memcached.c:3258
#4? 0x000000000040bfa1 in try_read_command (c=0x7ffff0013550) at memcached.c:3504
#5? 0x000000000040cc25 in drive_machine (c=0x7ffff0013550) at memcached.c:3824
#6? 0x000000000040d81f in event_handler (fd=37, which=2, arg=0x7ffff0013550) at memcached.c:4065
#7? 0x00007ffff7dc9e0c in event_process_active_single_queue (base=0x635bb0, flags=0) at event.c:1350
#8? event_process_active (base=0x635bb0, flags=0) at event.c:1420
#9? event_base_loop (base=0x635bb0, flags=0) at?? ?event.c:1621
#10 0x0000000000415416 in worker_libevent (arg=0x628d60) at thread.c:384
#11 0x0000003441607851 in start_thread () from /lib64/libpthread.so.0
#12 0x00000034412e890d in clone?? ?() from /lib64/libc.so.6


客戶(hù)端申請(qǐng)存儲(chǔ)key value會(huì)調(diào)用到do_item_alloc

/*@null@*/
item *do_item_alloc(char *key, const size_t nkey, const int flags,const rel_time_t exptime, const int nbytes,const uint32_t cur_hv) {uint8_t nsuffix;item *it = NULL;char suffix[40];size_t ntotal = item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix);if (settings.use_cas) {ntotal += sizeof(uint64_t);//算出需要分配的內(nèi)存的大小,原始長(zhǎng)度+結(jié)構(gòu)體自身大小}unsigned int id = slabs_clsid(ntotal);if (id == 0)return 0;mutex_lock(&cache_lock);/* do a quick check if we have any expired items in the tail.. */int tries = 5;int tried_alloc = 0;item *search;void *hold_lock = NULL;rel_time_t oldest_live = settings.oldest_live;search = tails[id];/* We walk up *only* for locked items. Never searching for expired.* Waste of CPU for almost all deployments */for (; tries > 0 && search != NULL; tries--, search=search->prev) {uint32_t hv = hash(ITEM_key(search), search->nkey, 0);/* Attempt to hash item lock the "search" item. If locked, no* other callers can incr the refcount*//* FIXME: I think we need to mask the hv here for comparison? */if (hv != cur_hv && (hold_lock = item_trylock(hv)) == NULL)continue;/* Now see if the item is refcount locked */if (refcount_incr(&search->refcount) != 2) {refcount_decr(&search->refcount);/* Old rare bug could cause a refcount leak. We haven't seen* it in years, but we leave this code in to prevent failures* just in case */if (search->time + TAIL_REPAIR_TIME < current_time) {itemstats[id].tailrepairs++;search->refcount = 1;do_item_unlink_nolock(search, hv);}if (hold_lock)item_trylock_unlock(hold_lock);continue;}/* Expired or flushed */if ((search->exptime != 0 && search->exptime < current_time)|| (search->time <= oldest_live && oldest_live <= current_time)) {itemstats[id].reclaimed++;if ((search->it_flags & ITEM_FETCHED) == 0) {itemstats[id].expired_unfetched++;}it = search;slabs_adjust_mem_requested(it->slabs_clsid, ITEM_ntotal(it), ntotal);do_item_unlink_nolock(it, hv);/* Initialize the item block: */it->slabs_clsid = 0;} else if ((it = slabs_alloc(ntotal, id)) == NULL) {


調(diào)用slabs_clsid()

//尋找適合給定大小的item存儲(chǔ)的slab
unsigned int slabs_clsid(const size_t size) {int res = POWER_SMALLEST;if (size == 0)return 0;while (size > slabclass[res].size)//找到第一個(gè)比item size大的slabif (res++ == power_largest)return 0;return res;
}

調(diào)用do_slabs_alloc返回slots指向的item,并使slots指向下一個(gè)item

/*存儲(chǔ)item*/
static void *do_slabs_alloc(const size_t size, unsigned int id) {slabclass_t *p;void *ret = NULL;item *it = NULL;if (id < POWER_SMALLEST || id > power_largest) {MEMCACHED_SLABS_ALLOCATE_FAILED(size, 0);return NULL;}p = &slabclass[id];assert(p->sl_curr == 0 || ((item *)p->slots)->slabs_clsid == 0);/* fail unless we have space at the end of a recently allocated page,we have something on our freelist, or we could allocate a new page *///p->sl_curr != 0 說(shuō)明還有空閑就不要調(diào)用do_slabs_newslab重新分配下一個(gè)pageif (! (p->sl_curr != 0 || do_slabs_newslab(id) != 0)) {/* We don't have more memory available */ret = NULL;} else if (p->sl_curr != 0) {/* return off our freelist */it = (item *)p->slots;//將當(dāng)前p空閑的slots其實(shí)也就是第一個(gè),實(shí)際上是鏈表最后一個(gè)chunk分配給itemp->slots = it->next;//修改p的空閑的slots,為倒數(shù)第二個(gè),也就是it的前一個(gè)if (it->next) it->next->prev = 0;//因?yàn)閕t的前一個(gè)再前一個(gè)已經(jīng)給item分配了,自然沒(méi)了p->sl_curr--;//-1,雖然perslab在分割好之后和sl_curr一樣大,但是sl_curr是要遞減的,而perslab是永遠(yuǎn)不變的存儲(chǔ)的是chunk個(gè)數(shù)ret = (void *)it;}if (ret) {p->requested += size;MEMCACHED_SLABS_ALLOCATE(size, id, p->size, ret);} else {MEMCACHED_SLABS_ALLOCATE_FAILED(size, id);}return ret;
}

下面是gdb下調(diào)試的函數(shù)調(diào)用關(guān)系:

#0? do_slabs_alloc (size=71, id=1) at slabs.c:241
#1? 0x000000000041161d in slabs_alloc (size=71, id=1) at slabs.c:404
#2? 0x0000000000412ae6 in do_item_alloc (key=0x7ffff0013754 "key", nkey=3, flags=0, exptime=0, nbytes=5, cur_hv=0) at items.c:188
#3? 0x0000000000415706 in item_alloc (key=0x7ffff0013754 "key", nkey=3, flags=0, exptime=0, nbytes=5) at thread.c:486
#4? 0x000000000040a38e in process_update_command (c=0x7ffff0013550, tokens=0x7ffff7ae4b00, ntokens=6, comm=2, handle_cas=false) at memcached.c:2917
#5? 0x000000000040b43d in process_command (c=0x7ffff0013550, command=0x7ffff0013750 "set") at memcached.c:3258
#6? 0x000000000040bfa1 in try_read_command (c=0x7ffff0013550) at memcached.c:3504
#7? 0x000000000040cc25 in drive_machine (c=0x7ffff0013550) at memcached.c:3824
#8? 0x000000000040d81f in event_handler (fd=37,?? ?which=2, arg=0x7ffff0013550) at memcached.c:4065
#9? 0x00007ffff7dc9e0c in event_process_active_single_queue (base=0x635bb0, flags=0) at event.c:1350
#10 event_process_active (base=0x635bb0, flags=0) at event.c:1420
#11 event_base_loop (base=0x635bb0, flags=0) at event.c:1621
#12 0x0000000000415416 in worker_libevent (arg=0x628d60) at thread.c:384
#13 0x0000003441607851 in start_thread () from /lib64/libpthread.so.0
#14 0x00000034412e890d in clone () from /lib64/libc.so.6

5.第一次slab_list

初始化slabs,分配trunk

static int do_slabs_newslab(const unsigned int id) {slabclass_t *p = &slabclass[id];
//settings.item_size_max = 1024 * 1024; /* The famous 1MB upper limit. */int len = settings.slab_reassign ? settings.item_size_max: p->size * p->perslab;char *ptr;if ((mem_limit && mem_malloced + len > mem_limit && p->slabs > 0) ||(grow_slab_list(id) == 0) ||((ptr = memory_allocate((size_t)len)) == 0)) {MEMCACHED_SLABS_SLABCLASS_ALLOCATE_FAILED(id);return 0;}memset(ptr, 0, (size_t)len);split_slab_page_into_freelist(ptr, id);
//這里很巧妙,如果是第一次do_slabs_newslab,那么p->slabs=0,++之后就=1,
//第二次來(lái)自然就是2,這次會(huì)把第2次申請(qǐng)的page也就是ptr串在p->slab_list[1]上p->slab_list[p->slabs++] = ptr;mem_malloced += len;MEMCACHED_SLABS_SLABCLASS_ALLOCATE(id);return 1;
}


p->slab_list第一次是存16*8個(gè)字節(jié)

//擴(kuò)充trunk數(shù)目,重新分配slabs個(gè)數(shù),默認(rèn)是分配16個(gè)頁(yè),后續(xù)按照2倍增加
static int grow_slab_list (const unsigned int id) {slabclass_t *p = &slabclass[id];if (p->slabs == p->list_size) {//默認(rèn)new_zise=16size_t new_size =  (p->list_size != 0) ? p->list_size * 2 : 16;//因?yàn)橐院髸?huì)擴(kuò)容,所以這里用realloc//p->slab_list一開(kāi)始=0,64位sizeof(void *)=8,32位sizeof(void *)=4void *new_list = realloc(p->slab_list, new_size * sizeof(void *));if (new_list == 0) return 0;p->list_size = new_size;p->slab_list = new_list;}return 1;
}

調(diào)用split_slab_page_into_freelist分割ptr


5.分割ptr

split_slab_page_into_freelist:

static void split_slab_page_into_freelist(char *ptr, const unsigned int id) {slabclass_t *p = &slabclass[id];int x;for (x = 0; x < p->perslab; x++) {do_slabs_free(ptr, 0, id);ptr += p->size;//ptr偏移一個(gè)size,第一次是96字節(jié),如果是默認(rèn)配置的話}
}

這個(gè)函數(shù)很短,就是循環(huán)去調(diào)用do_slabs_free函數(shù)

//分割item內(nèi)存
static void do_slabs_free(void *ptr, const size_t size, unsigned int id) {slabclass_t *p;item *it;//首先聲明一個(gè)item對(duì)象assert(((item *)ptr)->slabs_clsid == 0);assert(id >= POWER_SMALLEST && id <= power_largest);if (id < POWER_SMALLEST || id > power_largest)return;MEMCACHED_SLABS_FREE(size, id, ptr);p = &slabclass[id];//獲取第id個(gè)slabclass_t并聲明為pit = (item *)ptr;//將需要切割的內(nèi)存空間實(shí)例化為item *it->it_flags |= ITEM_SLABBED;it->prev = 0;//it一開(kāi)始無(wú)頭it->next = p->slots;//it的新卡一個(gè)是p的當(dāng)前的slots,也就是ptr上一次切割的item,也可以理解為是當(dāng)前item的上一個(gè)itemif (it->next) it->next->prev = it;//如果當(dāng)前的it的下一個(gè)item也就是也就是ptr上一次切割的item存在(第2次切割以后才會(huì)有)//前一個(gè)item的后一個(gè)item指向當(dāng)前,其實(shí)也就是正常的雙鏈表指向操作p->slots = it;//p的slots永遠(yuǎn)指向當(dāng)前的item,每次如果執(zhí)行do_slabs_free就會(huì)劃走一塊item,并串前后的指針p->sl_curr++;//p的當(dāng)前空閑的item個(gè)數(shù)+1p->requested -= size;return;
}

第一次:
(gdb) p?? ?ptr
$5 = 0x7ffff51e1010 ""

vs2012+?? ??? ?ptr?? ?0x0000000000230070 ""?? ?char *

>??? split_slab_page_into_freelist(ptr, id);

第二次:
(gdb) p?? ?ptr
$25 = (void *) 0x7ffff51e1070
0x70-0x10=0x60=96? 正好是一個(gè)chunk大小

第三次
(gdb) p ptr
$50 = (void *) 0x7ffff51e10d0
(gdb) p *(it-2)
$46 = {next = 0x7ffff51e1010, prev = 0x7ffff51e10d0, h_next = 0x0, time = 0, exptime = 0, nbytes = 0, refcount = 0, nsuffix = 0 '\000', it_flags = 4 '\004
', slabs_clsid = 0 '\000', nkey = 0 '\000', data = 0x7ffff51e1070}
(gdb) p *(it-4)
$54 = {next = 0x0, prev = 0x7ffff51e1070, h_next = 0x0, time = 0, exptime = 0, nbytes = 0, refcount = 0, nsuffix = 0 '\000', it_flags = 4 '\004', slabs_cl
sid = 0 '\000', nkey = 0 '\000', data = 0x7ffff51e1010}

為什么是it-2才是上一個(gè)呢?
因?yàn)?br /> (gdb) p sizeof(it)
$57 = 8
(gdb) p sizeof(item)
$58 = 48
it是指針自然是8字節(jié),而item結(jié)構(gòu)是48字節(jié),96正好是48的2倍,其實(shí)這里是巧合,求上一個(gè)item不應(yīng)該這么求!
static void split_slab_page_into_freelist(char *ptr, const unsigned int id) {
??? slabclass_t *p = &slabclass[id];
??? int x;
??? for (x = 0; x < p->perslab; x++) {
??????? do_slabs_free(ptr, 0, id);
??????? ptr += p->size;
??? }
}
因?yàn)槊看问荘tr增加p->size的長(zhǎng)度。
所以直接用next指針就可以了
(gdb) p it->next
$67 = (struct _stritem *) 0x7ffff51e1070
(gdb) p *it->next
$68 = {next = 0x7ffff51e1010, prev = 0x7ffff51e10d0, h_next = 0x0, time = 0, exptime = 0, nbytes = 0, refcount = 0, nsuffix = 0 '\000', it_flags = 4 '\004
', slabs_clsid = 0 '\000', nkey = 0 '\000', data = 0x7ffff51e1070}



下面是在vs2012下的調(diào)試數(shù)據(jù),一看就清楚了


7.分割完ptr之后

回到do_slabs_newslab中修改了p->slab_list[p->slabs++] = ptr;mem_malloced += len;


然后又回到do_slabs_alloc函數(shù)中:

it = (item *)p->slots;//將當(dāng)前p空閑的slots其實(shí)也就是第一個(gè),實(shí)際上是鏈表最后一個(gè)chunk分配給itemp->slots = it->next;//修改p的空閑的slots,為倒數(shù)第二個(gè),也就是it的前一個(gè)if (it->next) it->next->prev = 0;//因?yàn)閕t的前一個(gè)再前一個(gè)已經(jīng)給item分配了,自然沒(méi)了p->sl_curr--;//-1,雖然perslab在分割好之后和sl_curr一樣大,但是sl_curr是要遞減的,而perslab是永遠(yuǎn)不變的存儲(chǔ)的是chunk個(gè)數(shù)ret = (void *)it;
(gdb) p?? ?*p
$72 = {size = 96, perslab = 10922, slots = 0x7ffff52e0f70, sl_curr = 10922, slabs = 1, slab_list = 0x7ffff00169e0, list_size = 16, killing = 0, requested
= 0}
(gdb) n
(gdb) p *p
$73 = {size = 96, perslab = 10922, slots = 0x7ffff52e0f10, sl_curr = 10922, slabs = 1, slab_list = 0x7ffff00169e0, list_size = 16, killing = 0, requested

= 0}

?p->sl_curr--;之后的調(diào)試數(shù)據(jù),可以看到sl_curry已經(jīng)減1 ,而perslab是不變的。

(gdb) p *p
$75 = {size = 96, perslab = 10922, slots = 0x7ffff52e0f10, sl_curr = 10921, slabs = 1, slab_list = 0x7ffff00169e0, list_size = 16, killing = 0, requested
= 0}

下面是vs2012中的結(jié)果,一樣的:


8.分配好item之后

回到do_item_alloc,已經(jīng)得到分配的item

(gdb) p *it
$79 = {next = 0x7ffff52e0f10, prev = 0x0, h_next = 0x0, time = 0, exptime = 0, nbytes = 0, refcount = 0, nsuffix = 0 '\000', it_flags = 4 '\004', slabs_cl
sid = 0 '\000', nkey = 0 '\000', data = 0x7ffff52e0f70}


9.模擬memcached調(diào)用slabs


3次分配一樣大小的


2.故意設(shè)一個(gè)比默認(rèn)chunk=96大的需求設(shè)置100,從后面的調(diào)試信息可以看出id2已經(jīng)被算出應(yīng)該是第2個(gè)slabs上:

int main()
{item *it1=NULL;item *it2 = NULL;item *it3 = NULL;item *it4 = NULL;int preallocate = 0;size_t ntotal =63;// item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix);size_t ntotal2 =100;unsigned int id =0;	unsigned int id2 =0;settings_init();slabs_init(settings.maxbytes, settings.factor, preallocate);if (settings.use_cas) {ntotal += sizeof(uint64_t);}id=slabs_clsid(ntotal);it1=slabs_alloc(ntotal, id);it2=slabs_alloc(ntotal, id);it3=slabs_alloc(ntotal, id);if (settings.use_cas) {ntotal2 += sizeof(uint64_t);}id2=slabs_clsid(ntotal2);it4=slabs_alloc(ntotal2, id2);
return 0;
}


制造perslab=1的情景

分配超過(guò)settings.item_size_max / factor=717184的size

這樣就會(huì)命中id=41的slabs[41],同時(shí)我們?cè)O(shè)置2個(gè)需要分配717184的:

從調(diào)試結(jié)果可以看出來(lái)slabclass[41]已經(jīng)分配了2個(gè)slab_list,由于這2個(gè)slab_list指向的page都只有一個(gè)chunk,所以這個(gè)chunk中存儲(chǔ)的item的next和prev都是0,

因?yàn)榈谝淮畏指頳o_slabs_free的時(shí)候:

it->prev = 0;it->next = p->slots;
由于p->slots一開(kāi)始=0,因?yàn)楹竺娌粫?huì)再切割chunk了,所以這個(gè)item的next和prev都是0。

	item *it1=NULL;item *it2 = NULL;item *it3 = NULL;item *it4 = NULL;item *it5 = NULL;int preallocate = 0;size_t ntotal =63;// item_make_header(nkey + 1, flags, nbytes, suffix, &nsuffix);size_t ntotal2 =717184;unsigned int id =0;	unsigned int id2 =0;settings_init();slabs_init(settings.maxbytes, settings.factor, preallocate);if (settings.use_cas) {ntotal += sizeof(uint64_t);}id=slabs_clsid(ntotal);it1=slabs_alloc(ntotal, id);it2=slabs_alloc(ntotal, id);it3=slabs_alloc(ntotal, id);if (settings.use_cas) {ntotal2 += sizeof(uint64_t);}id2=slabs_clsid(ntotal2);it4=slabs_alloc(ntotal2, id2);it5=slabs_alloc(ntotal2, id2);

總結(jié)

以上是生活随笔為你收集整理的Memcached内存池分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。