(gdb) bt
#0 je_malloc (size=1) at src/jemalloc.c:1422
#1 0x00000000004316b3 in zmalloc (size=1) at zmalloc.c:125
#2 0x000000000043197c in zstrdup (s=0x6cf8c5 "") at zmalloc.c:215
#3 0x000000000042824c in initServerConfig () at server.c:1476
#4 0x000000000042e55a in main (argc=1, argv=0x7fffffffe408) at server.c:3984
je_malloc
ret = imalloc_body(size, &tsd, &usize);
imalloc_body
*tsd = tsd_fetch();
if (config_stats
*usize = s2u(size); 调整大小为8
imalloc(*tsd, size)
iallocztm(tsd, size, false, tcache_get(tsd, true), false, NULL)
先执行tcache_get(tsd, true)
tcache = tsd_tcache_get(tsd); 返回tsd的tcache字段
if (unlikely(tcache == NULL) && tsd_nominal(tsd)) { 第一次tcache为NULL
tcache = tcache_get_hard(tsd);
if (!tcache_enabled_get()) {
...
}
tsd = tsd_fetch();
tcache_enabled = tsd_tcache_enabled_get(tsd);返回tsd的tcache_enabled字段
if (tcache_enabled == tcache_enabled_default)
tcache_enabled = (tcache_enabled_t)opt_tcache; true->1->tcache_enabled_true
tsd_tcache_enabled_set(tsd, tcache_enabled);
arena = arena_choose(tsd, NULL);
unlikely((ret = tsd_arena_get(tsd)) == NULL)第一次为NULL,得到tsd的arena字段
ret = arena_choose_hard(tsd);
malloc_mutex_lock(&arenas_lock);
narenas_auto = 8
找到第一个空的null,a0 != NULL,所以第一次是a1,但是不一定选a1,因为a0当前线程数是0
arenas[choose]->nthreads == 0 || first_null == narenas_auto
ret = arenas[choose];
else
choose = first_null;
ret = arena_init_locked(choose);
arena_bind_locked(tsd, choose);
arena = arenas[ind];
arena->nthreads++;
tsd_arena_set(tsd, arena);设置tsd的arena字段
malloc_mutex_unlock(&arenas_lock);
tcache_create(tsd, arena)
((size_t)&(((tcache_t *)0)->tbins)) = 32 sizeof(tcache_bin_t) 32 je_nhbins 44
size = offsetof(tcache_t, tbins) + (sizeof(tcache_bin_t) * nhbins); 1440
stack_offset = size
size += stack_nelms * sizeof(void *); 3696 * 8 = 29568 31008
(gdb) p je_large_maxclass
$32 = 1835008
(gdb) p je_chunksize
$33 = 2097152
size = sa2u(size, CACHELINE);调整大小,32768
tcache = ipallocztm(tsd, size, CACHELINE, true, false, true, a0get()); tcache = false = 0 = NULL
ret = arena_palloc(tsd, arena, usize, alignment, zero, tcache);arena = a0get
ret = arena_malloc(tsd, arena, usize, zero, tcache);
arena = arena_choose(tsd, arena);
if (likely(tcache != NULL) && size <= tcache_maxclass) {
return (tcache_alloc_large(tsd, arena, tcache, size, zero));
} else
return (arena_malloc_large(arena, size, zero));
arena_run_t *run = arena_run_alloc_large(arena, usize + large_pad, zero);
32768 + 4096 = 36864
run = arena_run_alloc_large_helper(arena, size, zero);
arena_run_t *run = arena_run_first_best_fit(arena, s2u(size));
size_t search_size = run_quantize_first(size);
arena_chunk_map_misc_t *key = arena_miscelm_key_create(search_size);
return ((arena_chunk_map_misc_t *)
(arena_mapbits_size_encode(size) | CHUNK_MAP_KEY));
mapbits = size << CHUNK_MAP_SIZE_SHIFT; 53248 << 1
把size转换成1个地址
arena_chunk_map_misc_t *miscelm =
arena_avail_tree_nsearch(&arena->runs_avail, key);
在arena->runs_avail上面查找key大小
找不到,返回NULL
if (run != NULL) {
if (arena_run_split_large(arena, run, size, zero))
run = NULL;
}
return (run);
chunk = arena_chunk_alloc(arena);
chunk = arena_chunk_init_hard(arena);
chunk = arena_chunk_alloc_internal(arena, &zero, &commit);
chunk = chunk_alloc_cache(arena, &chunk_hooks, NULL, chunksize, chunksize, zero, true);
尝试从cache中分配
ret = chunk_recycle(arena, chunk_hooks, &arena->chunks_szad_cached,
&arena->chunks_ad_cached, true, new_addr, size, alignment, zero,
&commit, dalloc_node);
malloc_mutex_lock(&arena->chunks_mtx);
chunk_hooks_assure_initialized_locked(arena, chunk_hooks);
给chunk_hooks赋值,arena->chunk_hooks,arena_new时会赋值
chunk_hooks_default: chunk_alloc_default...
node = chunk_first_best_fit(arena, chunks_szad, chunks_ad, alloc_size);
extent_node_init(&key, arena, NULL, size, false, false);
创建一个node代表大小,去树上查找
return (extent_tree_szad_nsearch(chunks_szad, &key));
malloc_mutex_unlock(&arena->chunks_mtx);
return (NULL);
cache中没有,真正分配
chunk = arena_chunk_alloc_internal_hard(arena, &chunk_hooks, zero, commit);
malloc_mutex_unlock(&arena->lock);
chunk = (arena_chunk_t *)chunk_alloc_wrapper(arena, chunk_hooks, NULL,
chunksize, chunksize, zero, commit);
ret = chunk_hooks->alloc(new_addr, size, alignment, zero, commit,
arena->ind);
ret = chunk_alloc_core(arena, new_addr, size, alignment, zero,
commit, arena->dss_prec);
dss_prec=dss_prec_secondary
/* Retained. */
chunk_recycle
/* "primary" dss. */
chunk_alloc_dss(arena, new_addr, size, alignment, zero, commit)
/*
* mmap. Requesting an address is not implemented for
* chunk_alloc_mmap(), so only call it if (new_addr == NULL).
*/
chunk_alloc_mmap(size, alignment, zero, commit)
arena_chunk_register(arena, chunk, *zero)
extent_node_init(&chunk->node, arena, chunk, chunksize, zero, true);
给node的各个字段赋值
extent_node_achunk_set(&chunk->node, true);
return (chunk_register(chunk, &chunk->node));
rtree_set(&chunks_rtree, (uintptr_t)chunk, node)
key是chunk的地址,value是chunk的node字段
chunks_rtree在chunk_boot中创建
start_level = rtree_start_level(rtree, key);
key = chunk,140737326874624
start_level = rtree->start_level[lg_floor(key) >> LG_RTREE_BITS_PER_LEVEL];
RTREE_HEIGHT_MAX = 4
unsigned start_level[RTREE_HEIGHT_MAX];
2 2 1 0
rtree_level_t levels[RTREE_HEIGHT_MAX];
je_lg_floor(key) = 46
46 >> 4 = 2
start_level = 1
node = rtree_subtree_read(rtree, start_level);
subtree = rtree_subtree_tryread(rtree, level);
if (!rtree_node_valid(subtree))看subtree的地址是否比0x1大
subtree = atomic_read_p(&rtree->levels[level].subtree_pun);
return ((void *)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
atomic_add_p(p, NULL)交换并相加
uint64_t t = x;
asm volatile (
"lock; xaddq %0, %1;" 交换t(寄存器的值)和*p(内存),二者和送入*p
: "+r" (t), "=m" (*p) /* Outputs. */
: "m" (*p) /* Inputs. */
);
return (t + x);
return (subtree);
if (unlikely(!rtree_node_valid(subtree)))
subtree = rtree_subtree_read_hard(rtree, level);
第一次,创建
rtree_node_init(rtree, level, &rtree->levels[level].subtree)
atomic_cas_p((void **)elmp, NULL, RTREE_NODE_INITIALIZING)
atomic_cas_uint64((uint64_t *)p, (uint64_t)c, (uint64_t)s)
uint8_t success;
比较ax寄存器和*p(内存),
如果相等,s(寄存器)的值覆盖*p,zf置1
如果不等,*p的值覆盖ax,zf置0
设置ax寄存器的值(success的值)为zf
如果相等,即开始*p == 0, 之后*p = s, success = 1,返回0,
不等success=0,返回1
asm volatile (
"lock; cmpxchgq %4, %0;"
"sete %1;"
: "=m" (*p), "=a" (success) /* Outputs. */
: "m" (*p), "a" (c), "r" (s) /* Inputs. */
: "memory" /* Clobbers. */
);
return (!(bool)success);
node = rtree->alloc(ZU(1) << rtree->levels[level].bits);
rtree->levels[level].bits = 16
static rtree_node_elm_t * chunks_rtree_node_alloc(size_t nelms)
((rtree_node_elm_t *)base_alloc(nelms * sizeof(rtree_node_elm_t)));
(1<<16) * 8 = 512k
extent_node_init(&key, NULL, NULL, usize, false, false);
malloc_mutex_lock(&base_mtx);
node = extent_tree_szad_nsearch(&base_avail_szad, &key);
树上查找指定大小的node
if (node != NULL) {
/* Use existing space. */找到了先移除
extent_tree_szad_remove(&base_avail_szad, node);
} else {
/* Try to allocate more space. */
node = base_chunk_alloc(csize);没找到则分配
}
ret = extent_node_addr_get(node);
if (extent_node_size_get(node) > csize) {
extent_node_addr_set(node, (void *)((uintptr_t)ret + csize));
extent_node_size_set(node, extent_node_size_get(node) - csize);
extent_tree_szad_insert(&base_avail_szad, node);
得到部分内存,剩余创建一个node,放回树中
}
malloc_mutex_unlock(&base_mtx);
return ret;
if (node == NULL)
return (NULL);
atomic_write_p((void **)elmp, node);
atomic_write_uint64((uint64_t *)p, (uint64_t)x);
交换寄存器变量x和内存*p的值,即把node的地址赋给*elmp
asm volatile (
"xchgq %1, %0;" /* Lock is implied by xchgq. */
: "=m" (*p), "+r" (x) /* Outputs. */
: "m" (*p) /* Inputs. */
: "memory" /* Clobbers. */
);
返回node地址
return (subtree);
for (i = start_level; /**/; i++, node = child) {
subkey = rtree_subkey(rtree, key, i);
((key >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - rtree->levels[level].cumbits))
& ((ZU(1) << rtree->levels[level].bits) - 1));
1. 1 << 6 = 64
2. 64 - rtree->levels[1].cumbits = 64 - 32 = 32
3. key >> 32 = 32767
4. 1 << rtree->levels[1].bits = 1 << 16 = 65536
5. 32767 & (2^16 - 1) = 32767
第二次循环,level==2,rtree->levels[level].cumbits = 43
rtree->levels[1].bits = 11
(key >> (64 - 43)) & 2047 = 1971
if (i == rtree->height - 1) { rtree->height = 3
/* 第二次循环,进入这里
* node is a leaf, so it contains values rather than
* child pointers.
*/这时的node是第一次的child,subkey = 1971
rtree_val_write(rtree, &node[subkey], val);
atomic_write_p(&elm->pun, val);
xchgq指令,交换内存和寄存器
return (false);
}
assert(i + 1 < rtree->height);
child = rtree_child_read(rtree, &node[subkey], i);
rtree_node_elm_t *child;
child = rtree_child_tryread(elm);
child = elm->child;
if (!rtree_node_valid(child)) child的地址是否比1大
child = atomic_read_p(&elm->pun); 和NULL交换,并相加
return (child); 0x0
if (unlikely(!rtree_node_valid(child)))
child = rtree_child_read_hard(rtree, elm, level);
return rtree_node_init(rtree, level, &elm->child)
level = 1,
上面已经分析过,创建大小为ZU(1) << rtree->levels[level].bits的rtree_node_elm_t数组
起始地址写在elm->child中,并返回
return (child);
if (child == NULL)
return (true);
}
malloc_mutex_lock(&arena->lock);
return (chunk);
arena->stats.mapped += chunksize; 2M
arena->stats.metadata_mapped += (map_bias << LG_PAGE); 13 * 2 ^12 = 52k
flag_unzeroed = (zero || !commit) ? 0 : CHUNK_MAP_UNZEROED;
0
flag_decommitted = commit ? 0 : CHUNK_MAP_DECOMMITTED;
0
arena_mapbits_unallocated_set(chunk, map_bias, arena_maxrun,
flag_unzeroed | flag_decommitted); pageind = 13, 0x1f3000 1996k 留了4k一页
size_t *mapbitsp = arena_mapbitsp_get(chunk, pageind);
return (&arena_bitselm_get(chunk, pageind)->bits);
return (&chunk->map_bits[pageind-map_bias]); 0
arena_mapbitsp_write(mapbitsp,
arena_mapbits_size_encode(size) | CHUNK_MAP_BININD_INVALID | flags);
mapbits = size << CHUNK_MAP_SIZE_SHIFT; CHUNK_MAP_SIZE_SHIFT = 1
0x3e6000
CHUNK_MAP_BININD_INVALID = 0x1fe0
*mapbitsp = mapbits; 0x3e7fe0
arena_mapbits_unallocated_set(chunk, chunk_npages-1, arena_maxrun, flag_unzeroed);
pageind = 511
&chunk->map_bits[pageind-map_bias] 511 - 13 = 498
0x3e7fe0
return (chunk);
arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias);
13 512 - 13 = 499
(0x3e7fe0 >> 12) >> 1 = 499
arena_avail_tree_insert(&arena->runs_avail, arena_miscelm_get(chunk, pageind));
((arena_chunk_map_misc_t *)
((uintptr_t)chunk + (uintptr_t)map_misc_offset) + pageind - map_bias);
chunk + 4096 + 13 - 13
分配了一个arena_chunk_map_misc_t放到arena->runs_avail树中
return (chunk);
if (chunk != NULL) {
run = &arena_miscelm_get(chunk, map_bias)->run;
得到chunk + 4096 + 13 - 13位置的arena_chunk_map_misc_t的run字段
if (arena_run_split_large(arena, run, size, zero))
arena_run_split_large_helper(arena, run, size, true, zero)
36864
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
((void *)((uintptr_t)(a) & ~chunksize_mask))
run = (arena_run_t *) 0x7ffff6601010
chunk = (arena_chunk_t *) 0x7ffff6600000
miscelm = arena_run_to_miscelm(run);
arena_chunk_map_misc_t *miscelm =
(arena_chunk_map_misc_t*)
((uintptr_t)run - offsetof(arena_chunk_map_misc_t, run));
通过结构体字段地址得到结构体地址
run_ind = arena_miscelm_to_pageind(miscelm);
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm);
size_t pageind = ((uintptr_t)miscelm - ((uintptr_t)chunk + map_misc_offset))
/ sizeof(arena_chunk_map_misc_t) + map_bias;
map_misc_offset = 4096
0 + 13
chunk_npages > pageind >= map_bias
flag_dirty = arena_mapbits_dirty_get(chunk, run_ind);
mapbits = arena_mapbits_get(chunk, pageind);
return (arena_mapbitsp_read(arena_mapbitsp_get(chunk, pageind)));
&arena_bitselm_get(chunk, pageind)->bits
&chunk->map_bits[pageind-map_bias] 13 - 13
0x3e7fe0
return (mapbits & CHUNK_MAP_DIRTY); 0x10
0x0
flag_decommitted = arena_mapbits_decommitted_get(chunk, run_ind);
mapbits & CHUNK_MAP_DECOMMITTED 0x04
0x0
need_pages = (size >> LG_PAGE);0x9000>>12 = 9
arena_run_split_remove(arena, chunk, run_ind, flag_dirty, flag_decommitted, need_pages);
total_pages = arena_mapbits_unallocated_size_get(chunk, run_ind) >> LG_PAGE;
&chunk->map_bits[pageind-map_bias] 13 - 13
(mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT;
CHUNK_MAP_SIZE_MASK = ~(((size_t)0xffU) << 5 | ((size_t)0x1cU) | ((size_t)0x3U))
0xffffffffffffe000
0x3e6000 >> 1 = 0x1f3000 1996k >> 12 = 499
rem_pages = total_pages - need_pages; 490
arena_avail_remove(arena, chunk, run_ind, total_pages);
arena_avail_tree_remove(&arena->runs_avail, arena_miscelm_get(chunk, pageind));
从树runs_avail上移除arena_chunk_map_misc_t
arena_cactive_update(arena, need_pages, 0);
统计atomic_add_z(&stats_cactive, size);
"lock; xaddq %0, %1;"交换相加
arena->nactive += need_pages;
flags = 0
flag_unzeroed_mask = CHUNK_MAP_UNZEROED = 8
arena_mapbits_unallocated_set(chunk, run_ind+need_pages,
(rem_pages << LG_PAGE), flags |
(arena_mapbits_unzeroed_get(chunk, run_ind+need_pages) &
flag_unzeroed_mask));
13 + 9 = 22, 490 << 12
&chunk->map_bits[pageind-map_bias] 22 - 13 = 9
arena_mapbits_unallocated_set(chunk, run_ind+total_pages-1,
(rem_pages << LG_PAGE), flags |
(arena_mapbits_unzeroed_get(chunk, run_ind+total_pages-1) &
flag_unzeroed_mask));
13 + 499 - 1 = 511, 490 << 12
&chunk->map_bits[pageind-map_bias] 511- 13 = 498
arena_avail_insert(arena, chunk, run_ind+need_pages, rem_pages);
pageind = 13 + 9 = 22, rem_pages = 490
arena_avail_tree_insert(&arena->runs_avail, arena_miscelm_get(chunk, pageind));
((arena_chunk_map_misc_t *)((uintptr_t)chunk + (uintptr_t)map_misc_offset) + pageind-map_bias);
arena_chunk_map_misc_t数组的[pageind-map_bias]元素
flag_unzeroed_mask = CHUNK_MAP_UNZEROED = 8
arena_mapbits_large_set(chunk, run_ind+need_pages-1, 0,
flag_dirty |
(flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, run_ind+need_pages-1)));
13 + 9 -1 = 21,21 -13 = 8
size = 0,
arena_mapbits_size_encode(size) | CHUNK_MAP_BININD_INVALID | flags | CHUNK_MAP_LARGE | CHUNK_MAP_ALLOCATED
0x1fe0,或完0x1fe3
arena_mapbits_large_set(chunk, run_ind, size,
flag_dirty |
(flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, run_ind)));
13, 13 -13 = 0
*mapbitsp = 0x3e7fe0旧值,mapbits & CHUNK_MAP_UNZEROED = 0
size = 36864 0x9000
size encode 0x12000
0x12000,或完0x13fe3
return (false);
run = NULL;返回false,不会执行NULL
return (run);
}
miscelm = arena_run_to_miscelm(run);
run字段得到结构体miscelm地址
ret = (void *)((uintptr_t)arena_miscelm_to_rpages(miscelm) + random_offset);
arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm);
size_t pageind = arena_miscelm_to_pageind(miscelm);
得到chunk地址,miscelm - (chunk + offset),arena_chunk_map_misc_t数组第几个元素 + map_bias
size_t pageind = ((uintptr_t)miscelm - ((uintptr_t)chunk + map_misc_offset))
/ sizeof(arena_chunk_map_misc_t) + map_bias;
13
return ((void *)((uintptr_t)chunk + (pageind << LG_PAGE)));
得到第13页的首地址
random_offset = 2880
szind_t index = size2index(usize) - NBINS; 43 - 39 = 4
意思是NBINS之下是小内存分配,不在这里统计()
arena->stats.nmalloc_large++;
arena->stats.nrequests_large++;
arena->stats.allocated_large += usize;
arena->stats.lstats[index].nmalloc++;
arena->stats.lstats[index].nrequests++;
arena->stats.lstats[index].curruns++;
malloc_mutex_unlock(&arena->lock);
return (ret);
if (config_cache_oblivious)
ret = (void *)((uintptr_t)ret & ~PAGE_MASK);去掉了page零头
return (ret);
arena_metadata_allocated_add(iaalloc(ret), isalloc(ret,config_prof));
arena_aalloc(ptr) 后执行
return (extent_node_arena_get(&chunk->node));
je_extent_node_arena_get函数
return (node->en_arena); arena_t *
arena_salloc(ptr, demote) 先执行
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
0x7ffff660d000 - 0x7ffff6600000
13
binind = arena_mapbits_binind_get(chunk, pageind);
&chunk->map_bits[pageind-map_bias]
0x13fe3
binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT;
CHUNK_MAP_BININD_MASK = 0xff, CHUNK_MAP_BININD_SHIFT = 5
取mapbits的5-12位,0xff
ret = arena_mapbits_large_size_get(chunk, pageind) - large_pad
&chunk->map_bits[pageind-map_bias] 13 -13
0x13fe3
size = (mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT;
(gdb) p /x (0x13fe3 & 0xffffffffffffe000)
$338 = 0x12000
(gdb) p /x (0x13fe3 & 0xffffffffffffe000) >> 1
$339 = 0x9000
0x9000 - 4096 = 0x8000
arena_mapbits_dirty_get(chunk, pageind) == arena_mapbits_dirty_get(chunk, pageind+((ret+large_pad)>>LG_PAGE)-1)
13 == 13 + 9 - 1 21
return (ret);
atomic_add_z(&arena->stats.metadata_allocated, size);
(&chunk->node)->en_arena->stats.metadata_allocated
xaddq交换并相加
return (ret);0x7ffff660d000
tcache_arena_associate(tcache, arena);
config_stats == 1
malloc_mutex_lock(&arena->lock);
ql_elm_new(tcache, link);
ql_tail_insert(&arena->tcache_ql, tcache, link); tcache保存在arena->tcache_ql队列
malloc_mutex_unlock(&arena->lock);
for (i = 0; i < nhbins; i++) 44 stack_offset = 1440,初始值
tcache->tbins[i].lg_fill_div = 1;
tcache->tbins[i].avail = (void **)((uintptr_t)tcache + (uintptr_t)stack_offset);
stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *);
return tcache;
tcache_get_hard return
tsd_tcache_set(tsd, tcache);
tsd的tcache字段赋值
return (tcache);
}
ret = arena_malloc(tsd, arena, size, zero, tcache); size = 1
arena = arena_choose(tsd, arena);
ret = tsd_arena_get(tsd)得到tsd的arena字段
size <= SMALL_MAXCLASS tcache != NULL
SMALL_MAXCLASS = 10k以内都用tcache,large_maxclass = 0x1c0000 7 * 2^18 = 1792k(1M多),之上就是huge了
tcache_maxclass = 32k,只要小于32k,都可以用tcache
tcache_alloc_small(tsd, arena, tcache, size, zero) size = 1
binind = size2index(size); 0
usize = index2size(binind); 8
tbin = &tcache->tbins[binind];
ret = tcache_alloc_easy(tbin);
第一次tbin->ncached == 0
tbin->low_water = -1;
return (NULL);
ret = tcache_alloc_small_hard(tsd, arena, tcache, tbin, binind);
arena_tcache_fill_small(arena, tbin, binind, config_prof ? tcache->prof_accumbytes : 0);
arena_bin_t *bin = &arena->bins[binind];
malloc_mutex_lock(&bin->lock);
for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >> tbin->lg_fill_div); i < nfill; i++)
je_tcache_bin_info[binind].ncached_max = 200,tbin->lg_fill_div = 1
初始化i = 0, nfill = 200 >> 1 = 100,连续填充100个
arena_run_t *run;
void *ptr;
if ((run = bin->runcur) != NULL && run->nfree > 0)
ptr = arena_run_reg_alloc(run, &arena_bin_info[binind]);第二次填充就会调用,第一次下面也会调
else
ptr = arena_bin_malloc_hard(arena, bin); 第一次分配走这里
binind = arena_bin_index(arena, bin);
szind_t binind = bin - arena->bins;带类型指针相减,结果是偏移,0
bin_info = &arena_bin_info[binind]; 全局的arena_bin_info
bin->runcur = NULL;
run = arena_bin_nonfull_run_get(arena, bin);
run = arena_bin_nonfull_run_tryget(bin);
arena_run_t *run = arena_bin_runs_first(bin);
arena_chunk_map_misc_t *miscelm = arena_run_tree_first(&bin->runs);
bin->runs是个rb树,树中节点是arena_chunk_map_misc_t,
最小的元素就是地址最小的arena_chunk_map_misc_t
第一次为NULL
if (run != NULL) {
arena_bin_runs_remove(bin, run);
if (config_stats)
bin->stats.reruns++;
}
return (run)第一次返回NULL
binind = arena_bin_index(arena, bin);
bin_info = &arena_bin_info[binind];
malloc_mutex_unlock(&bin->lock);是不是写反了
malloc_mutex_lock(&arena->lock);
run = arena_run_alloc_small(arena, bin_info->run_size, binind);
binind = 0,bin_info->run_size = 4096
run = arena_run_alloc_small_helper(arena, size, binind);
arena_run_t *run = arena_run_first_best_fit(arena, size);
size_t search_size = run_quantize_first(size);
size_t qsize = run_quantize(size);
if (size <= small_maxrun && small_run_tab[size >> LG_PAGE])
7k,small_run_tab[1] = true
return (size);
if (qsize < size) {
/*
* Skip a quantization that may have an adequately large run,
* because under-sized runs may be mixed in. This only happens
* when an unusual size is requested, i.e. for aligned
* allocation, and is just one of several places where linear
* search would potentially find sufficiently aligned available
* memory somewhere lower.
*/
qsize = run_quantize_next(size);
}
return (qsize); 4096
arena_chunk_map_misc_t *key = arena_miscelm_key_create(search_size);
((arena_chunk_map_misc_t *)(arena_mapbits_size_encode(size) | CHUNK_MAP_KEY));
4096 << 1 = 8k 0x2001 CHUNK_MAP_KEY=0x1
arena_chunk_map_misc_t *miscelm = arena_avail_tree_nsearch(&arena->runs_avail, key);
在arena->runs_avail中查找key
arena->runs_avail是个红黑树,树中节点类型是arena_chunk_map_misc_t
比较函数是arena_avail_comp,a,b比较,a有可能是key(根据CHUNK_MAP_KEY来区分),
如果是key,调用arena_miscelm_key_size_get(a)得到其大小,
(mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT;
& 0xffffffffffffe000 >> 1
否则通过arena_miscelm_size_get()得到其大小,miscelm代表一个地址
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); 去掉位数
pageind = arena_miscelm_to_pageind(miscelm);
(数组元素(miscelm)地址 - (chunk + 数组起始偏移))/sizeof(arena_chunk_map_misc_t)
= 数组元素个数,几个元素,就是第几页,再加上map_bias,9 + 13 = 22
mapbits = arena_mapbits_get(chunk, pageind);
&chunk->map_bits[pageind-map_bias]
*mapbitsp = 0x3d5fe0
(mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT;
return (arena_mapbits_size_decode(mapbits));
size = 0x1ea000
调用run_quantize,获取调整后的大小
4096 --> 4096
0x1ea000 --> 0x1c1000, large_pad = 4096
qsize = index2size(size2index(size - large_pad + 1) - 1) + large_pad;
if (miscelm == NULL)
return (NULL);
return (&miscelm->run);能找到
if (run != NULL) {
if (arena_run_split_small(arena, run, size, binind))
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run);
去掉零头
miscelm = arena_run_to_miscelm(run);
arena_chunk_map_misc_t *miscelm =
(arena_chunk_map_misc_t*)
((uintptr_t)run - offsetof(arena_chunk_map_misc_t, run));
通过字段地址得到结构体的地址
run_ind = arena_miscelm_to_pageind(miscelm);
22
flag_dirty = arena_mapbits_dirty_get(chunk, run_ind);
&chunk->map_bits[pageind-map_bias]
0x3d5fe0 & 0x10U
flag_decommitted = arena_mapbits_decommitted_get(chunk, run_ind);
0x04U
need_pages = (size >> LG_PAGE); 1
arena_run_split_remove(arena, chunk, run_ind, flag_dirty, flag_decommitted, need_pages);
total_pages = arena_mapbits_unallocated_size_get(chunk, run_ind) >> LG_PAGE;
0x3d5fe0 & CHUNK_MAP_SIZE_MASK >> CHUNK_MAP_SIZE_SHIFT >> 12
后13位清0,0x3d4000,右移1位,0x1ea000,右移12位,0x1ea = 490
rem_pages = total_pages - need_pages;
arena_avail_remove(arena, chunk, run_ind, total_pages);
arena_avail_tree_remove(&arena->runs_avail, arena_miscelm_get(chunk,pageind));
从arena的runs_avail树中移除arena_chunk_map_misc_t节点
arena_cactive_update(arena, need_pages, 0);
ssize_t cactive_diff = CHUNK_CEILING((arena->nactive + add_pages
- sub_pages) << LG_PAGE) - CHUNK_CEILING(arena->nactive <<
LG_PAGE);
CHUNK_CEILING(9 + 1 - 0 << 12)没有1个chunk大小,变成1个chunk大小
两者都是0
if (cactive_diff != 0)
stats_cactive_add(cactive_diff);
arena->nactive += need_pages;
size_t flags = flag_dirty | flag_decommitted;
size_t flag_unzeroed_mask = (flags == 0) ? CHUNK_MAP_UNZEROED :0;
arena_mapbits_unallocated_set(chunk, run_ind+need_pages, 1
(rem_pages << LG_PAGE), flags |
(arena_mapbits_unzeroed_get(chunk, run_ind+need_pages) &
flag_unzeroed_mask));
run_ind = 22, need_pages = 1, total_pages = 490
&chunk->map_bits[ 23 - 13] 原来是0
arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) | CHUNK_MAP_BININD_INVALID | flags);
size 0x1e9000,encode之后0x3d2000,或上之后0x3d3fe0,CHUNK_MAP_BININD_INVALID = 0x1fe0
arena_mapbits_unallocated_set(chunk, run_ind+total_pages-1,
(rem_pages << LG_PAGE), flags |
(arena_mapbits_unzeroed_get(chunk, run_ind+total_pages-1) &
flag_unzeroed_mask));
arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) | CHUNK_MAP_BININD_INVALID | flags);
&chunk->map_bits[511 - 13]
之前是0x3d5fe0
CHUNK_MAP_UNZEROED = 0x08
0x1e9000 0x3d3fe0
if (flag_dirty != 0) {
arena_run_dirty_insert(arena, chunk, run_ind+need_pages,
rem_pages);
}
arena_avail_insert(arena, chunk, run_ind+need_pages, rem_pages);
重新插入,重点是pageind是run_ind+need_pages,前移了,代表下一个空闲页
arena_avail_tree_insert(&arena->runs_avail, arena_miscelm_get(chunk, pageind));
for (i = 0; i < need_pages; i++) {
size_t flag_unzeroed = arena_mapbits_unzeroed_get(chunk, run_ind+i);
&chunk->map_bits[pageind-map_bias] 22 - 13
0x3d5fe0
0
arena_mapbits_small_set(chunk, run_ind+i, i, binind, flag_unzeroed);
pageind = run_ind+i = 22, runind = binind = 0, i= 0,0
&chunk->map_bits[22-13]
arena_mapbitsp_write(mapbitsp, (runind << CHUNK_MAP_RUNIND_SHIFT) |
(binind << CHUNK_MAP_BININD_SHIFT) | flags | CHUNK_MAP_ALLOCATED);
0x1
if (config_debug && flag_dirty == 0 && flag_unzeroed == 0) 条件不满足
arena_run_page_validate_zeroed(chunk, run_ind+i);
}
如果split失败
run = NULL;
}
return (run);
if (run != NULL) {
/* Initialize run internals. */
run->binind = binind; 0
run->nfree = bin_info->nregs; 512
bitmap_init(run->bitmap, &bin_info->bitmap_info);
run的bitmap数组,大小BITMAP_GROUPS_MAX = 9
#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2
9 <= 12
# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS)
BITMAP_MAXBITS 1 << 9 = 512
BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)
BITMAP_GROUPS_L0(nbits) + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
BITMAP_BITS2GROUPS(nbits) + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS)
(512 + 63) >> 6 = 8 (9 + 63) >> 6 = 1
8 + 1 = 9
memset(bitmap, 0xffU, binfo->levels[binfo->nlevels].group_offset << LG_SIZEOF_BITMAP);
{nbits = 512, nlevels = 2, levels = {{group_offset = 0}, {group_offset = 8}, {group_offset = 9}, {group_offset = 0}}}
9 << 3 = 9 * 8 = 72,9个long
初始化这个数组
extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK))
& BITMAP_GROUP_NBITS_MASK;
(64 - (512 & 63)) & 63 = 0
if (extra != 0)
bitmap[binfo->levels[1].group_offset - 1] >>= extra;
for (i = 1; i < binfo->nlevels; i++) { 2
size_t group_count = binfo->levels[i].group_offset -
binfo->levels[i-1].group_offset; 8 - 0
extra = (BITMAP_GROUP_NBITS - (group_count &
BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK;
(64 - (8 & 63)) & 63 = 56
if (extra != 0)
bitmap[binfo->levels[i+1].group_offset - 1] >>= extra;
bitmap[9 - 1] >>= extra; 右移前,是-1,右移后是0xff
}
}
malloc_mutex_unlock(&arena->lock);
malloc_mutex_lock(&bin->lock);
if (run != NULL) {
if (config_stats) {
bin->stats.nruns++; 0->1
bin->stats.curruns++;
}
return (run);
}
bin->runcur = run;
bin->runcur->nfree = 512
return (arena_run_reg_alloc(bin->runcur, bin_info));
regind = bitmap_sfu(run->bitmap, &bin_info->bitmap_info);
i = binfo->nlevels - 1; 2 - 1
g = bitmap[binfo->levels[i].group_offset]; 8
0xff,第一次第二次都一样
bit = jemalloc_ffsl(g) - 1;
__builtin_ffsl,返回右起第一个1的位置,从1开始,1 - 1 = 0
while (i > 0) {
i--;
g = bitmap[binfo->levels[i].group_offset + bit]; 0 + 0
-1,第二次-2
bit = (bit << LG_BITMAP_GROUP_NBITS) + (jemalloc_ffsl(g) - 1);
0,第二次bit = 0 + 1 = 1
}
bitmap_set(bitmap, binfo, bit);
goff = bit >> LG_BITMAP_GROUP_NBITS; 0,第二次1>>6 = 0
当bit=64时,goff就不等于0了,因为1个long就是64位
bitmap_t *gp = &bitmap[goff];
bitmap_t g = *gp;
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
(bit = 0)-2,第二次(bit = 1)g^(1 << (1 & 63)) = g ^ 2 = -4, (bit=2)-8, (bit=3)-16, (bit=4)-32
逐步蚕食
bit = 63,g只剩最高位1个1,和(size_t)1<<63相等,异或后为0
*gp = g;
/* Propagate group state transitions up the tree. */
if (g == 0) { 这里没走到,当bit=63时可以走到
unsigned i;
for (i = 1; i < binfo->nlevels; i++) { 2
bit = goff; 0, goff也可能为1
goff = bit >> LG_BITMAP_GROUP_NBITS; 0 >> 6,1>>6 = 0,除非原来的goff=64,新的goff=1
gp = &bitmap[binfo->levels[i].group_offset + goff]; bitmap[8]
g = *gp;
assert(g & (1LU << (bit & BITMAP_GROUP_NBITS_MASK)));
g ^= 1LU << (bit & BITMAP_GROUP_NBITS_MASK);
0xff->0xfe
*gp = g; 改变bitmap[8]
if (g != 0)
break;
}
}
这个函数改变了bitmap某个元素的值
return (bit); 返回0
miscelm = arena_run_to_miscelm(run);
字段地址得到结构体地址
rpages = arena_miscelm_to_rpages(miscelm);
return ((void *)((uintptr_t)chunk + (pageind << LG_PAGE))); 22
ret = (void *)(
(uintptr_t)rpages +
(uintptr_t)bin_info->reg0_offset + 0
(uintptr_t)(bin_info->reg_interval * regind) 8 * 0,第二次8 * 1
);
run->nfree--;
return (ret);
end arena_bin_malloc_hard
end else
tbin->avail[nfill - 1 - i] = ptr; 100 - 1 - 0
end for
malloc_mutex_unlock(&bin->lock);
地址递减,因为是从大到小填充的
(gdb) p tbin->avail[0]
$245 = (void *) 0x7ffff6616318
(gdb) p tbin->avail[1]
$246 = (void *) 0x7ffff6616310
(gdb) p tbin->avail[2]
$247 = (void *) 0x7ffff6616308
(gdb) p tbin->avail[100]
$248 = (void *) 0x0
(gdb) p tbin->avail[99]
$249 = (void *) 0x7ffff6616000 rpages的地址
tbin->ncached = i; 100
end arena_tcache_fill_small
ret = tcache_alloc_easy(tbin);
tbin->ncached--;
ret = tbin->avail[tbin->ncached];
return (ret);
end je_tcache_alloc_small_hard
assert(tcache_salloc(ret) == usize);
由指针地址得到chunk地址,pageind,进而拿到pageind的arena_mapbits_large_get(chunk, pageind)
mapbits中包含binind,进而可以得到usize
binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT;
tbin->tstats.nrequests++;
tcache_event(tsd, tcache);
tcache->ev_cnt++;
#define TCACHE_GC_SWEEP 8192
/* Number of tcache allocation/deallocation events between incremental GCs. */
#define TCACHE_GC_INCR \ 210 + 1
((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1))
if (unlikely(tcache->ev_cnt == TCACHE_GC_INCR))
tcache_event_hard(tsd, tcache); do gc 这里没走到
return (ret);
end tcache_alloc_small
end arena_malloc
return ret
end je_iallocztm
end imalloc
end imalloc_body
*tsd_thread_allocatedp_get(tsd) += usize;
tsd->thread_allocated += 8
return ret
end je_malloc
update_zmalloc_stat_alloc(zmalloc_size(ptr));
#define zmalloc_size(p) je_malloc_usable_size(p)
isalloc(ptr, config_prof);
arena_salloc(ptr, demote) demote = false
上面已经分析过,为ret = index2size(binind); 8
__sync_add_and_fetch(&used_memory, (__n))
return ptr;
end zmalloc