fini=
#5 0x000000000041d769 in _start ()
在main函数被调用之前
JEMALLOC_ATTR(constructor) static void jemalloc_constructor(void)
{
malloc_init();
}
jemalloc.c---->#include "jemalloc/internal/jemalloc_internal.h"---->系统没有定义JEMALLOC_JET,所以有下面定义
# define JEMALLOC_N(n) je_##n
# include "../jemalloc.h"
---->
#define JEMALLOC_HAVE_ATTR
define JEMALLOC_ATTR(s) __attribute__((s))
所以JEMALLOC_ATTR(constructor)展开就是__attribute__((constructor))
malloc_mutex_lock(&init_lock);
malloc_init_hard_needed,判断malloc_initializer是否为空,决定是否等待malloc_init_state置为malloc_init_initialized
malloc_init_hard_a0_locked
malloc_conf_init
1--->读配置文件"/etc/je_malloc.conf"
2--->读环境变量"JE_MALLOC_CONF"
base_boot
malloc_mutex_init(&base_mtx)
(gdb) bt
#0 je_malloc_mutex_init (mutex=0x91cd60
#1 0x000000000061c4d3 in je_base_boot () at src/base.c:147
#2 0x00000000004da5c7 in malloc_init_hard_a0_locked () at src/jemalloc.c:1194
#3 0x00000000004da899 in malloc_init_hard () at src/jemalloc.c:1324
#4 0x00000000005dbf09 in malloc_init () at src/jemalloc.c:285
#5 jemalloc_constructor () at src/jemalloc.c:2515
#6 0x00000000006ce75d in __libc_csu_init ()
#7 0x00007ffff730ee55 in __libc_start_main (main=0x42e4b8
fini=
#8 0x000000000041d769 in _start ()
base_boot为什么带上je_前缀了呢,是因为前面定义了# define JEMALLOC_N(n) je_##n
在private_namespace.h中,有#define base_boot JEMALLOC_N(base_boot)
jemalloc_internal.h无条件包含了private_namespace.h
AC_CONFIG_COMMANDS([include/jemalloc/internal/private_namespace.h], [
mkdir -p "${objroot}include/jemalloc/internal"
"${srcdir}/include/jemalloc/internal/private_namespace.sh" "${srcdir}/include/jemalloc/internal/private_symbols.txt" > "${objroot}include/jemalloc/internal/private_namespace.h"
], [
srcdir="${srcdir}"
objroot="${objroot}"
])
private_namespace.h是生成的,通过private_symbols.txt文件生成
gcc在预处理时,要替换全部的宏,所以函数名base_boot变成了je_base_boot
在confiure时加了选项--with-jemalloc-prefix=je_,通过查看configure.ac,依次是JEMALLOC_PREFIX,
这是对public符号(提供给外部用户的函数)定义宏
extent_tree_szad_new(&base_avail_szad);
/* Generate red-black tree functions. */
rb_gen(, extent_tree_szad_, extent_tree_t, extent_node_t, szad_link,
extent_szad_comp)
生成一组红黑树操作函数,这组函数的前缀是extent_tree_szad_,树的类型是extent_tree_t(存储树的根节点)
节点类型extent_node_t,将各个节点连接起来的是extent_node_t的szad_link字段,比较函数是extent_szad_comp
这里也就是创建一个红黑树base_avail_szad
chunk_boot
opt_lg_chunk = 21
je_chunksize = 1<<21 = 0x200000 = 2M
je_chunksize_mask = 0x1fffff
je_chunk_npages = chunksize >> LG_PAGE = 2M >> 12 = 2M / 4k = 512
chunk_dss_boot
malloc_mutex_init(&dss_mtx)
dss_base = chunk_dss_sbrk(0);//sbrk(0) 数据区域的末尾地址,再往上是heap段
dss_prev = dss_max = dss_base
rtree_new(&chunks_rtree,... rtree是个复杂的数据结构,多维查找
ctl_boot
malloc_mutex_init(&ctl_mtx)
arena_boot
arena_lg_dirty_mult_default_set(opt_lg_dirty_mult);
atomic_write_z((size_t *)&lg_dirty_mult_default, (size_t)lg_dirty_mult);
asm volatile (
"xchgq %1, %0;" /* Lock is implied by xchgq. */ *p来自内存,x来自寄存器,交换2个变量的值
: "=m" (*p), "+r" (x) /* Outputs. */
: "m" (*p) /* Inputs. */
: "memory" /* Clobbers. */ 改变内存的值
);
初始化:map_bias=0,((size_t)&(((arena_chunk_t *)0)->map_bits)) = 104,
((sizeof(arena_chunk_map_bits_t) + sizeof(arena_chunk_map_misc_t)) = 8 + 96
LG_PAGE = 12,PAGE_MASK = ((size_t)(PAGE - 1)) = ((size_t)((1U << LG_PAGE) - 1)) = 4k - 1
迭代三次,
header_size = 104 + (8+96)* (512 - map_bias)
map_bias = (header_size + PAGE_MASK) >> LG_PAGE;(1结果是1。4097,结果也是1)
第一次,header_size=53352,map_bias = 14
第二次,header_size=51896,je_map_bias=13
第三次,header_size=52000,je_map_bias=13
map_misc_offset = 104 + 8*(512 - 13) = 4096
arena_maxrun = chunksize - (map_bias << LG_PAGE); = 2M - 13 * 4096 = 2043904
large_maxclass = index2size(size2index(chunksize)-1);
size2index_compute(2M)
x = je_lg_floor(4M-1)
asm ("bsr %1, %0"
: "=r"(ret) // Outputs. 找到x的二进制表示,最高位1是第几个数,从右开始,从0开始
: "r"(x) // Inputs.
) = 21, 第21位,最高位的1
shift = x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); = 21 - (2 + 3) = 16
grp = shift << LG_SIZE_CLASS_GROUP; 16 << 2 = 64
lg_delta = x - LG_SIZE_CLASS_GROUP - 1 = 21 -2 -1 = 18
delta_inverse_mask = ZI(-1) << lg_delta 0xfffffffffffc0000
mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
(((2M - 1) & delta_inverse_mask) >> 18) & ((1 << 2) - 1) = 3
清空2M - 1的后18位,并右移,取后三位
index = NTBINS + grp + mod; = 0 + 64 + 3 = 67
index2size_lookup(szind_t index)
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
((ZU(1)<
(1 << 3) +
SC( 1, 3, 3, 1, yes, 3)
(1<<3) + 1<<3
SC( 2, 3, 3, 2, yes, 3)
(1<<3) + 2<<3
SC( 38, 13, 11, 3, yes, no)
38是最后一个yes,
1<<13 + 3<<11 = 14336
SC(238, 63, 61, 3, no, no)
1<<63 + 3<<61 = 2^63 + 3 * 2^61 = 14336
size_t index2size_tab[NSIZES(239)] = {8,16,24,...,16140901064495857664}
index = 66
SC( 66, 20, 18, 3, no, no)
1<<20 + 3<<18 = 2^20 + 3*2^18= 1835008
index2size_compute
je_large_maxclass = 1835008
nlclasses = size2index(large_maxclass) - size2index(SMALL_MAXCLASS);14336
66 - 38 = 28
nhclasses = NSIZES - nlclasses - NBINS;
172 = 239 - 28 - 39
bin_info_init
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
BIN_INFO_INIT_bin_##bin(index, (ZU(1)<
BIN_INFO_INIT_bin_yes(0, (1 << 3) + 0)
arena_bin_info[0].reg_siz = 8
bin_info_run_size_calc(arena_bin_info[0])
SC( 1, 3, 3, 1, yes, 3)
BIN_INFO_INIT_bin_yes(1, (1<<3) + 1<<3)
...
SC(238, 63, 61, 3, no, no)
BIN_INFO_INIT_bin_no(1, 1<<63 + 3<<61)
#define BIN_INFO_INIT_bin_yes(index, size) \
bin_info = &arena_bin_info[index]; \
bin_info->reg_size = size; \
bin_info_run_size_calc(bin_info); \
arena_bin_info_t arena_bin_info[NBINS];39
/*
* Calculate bin_info->run_size such that it meets the following constraints:
*
* *) bin_info->run_size <= arena_maxrun 2043904
* *) bin_info->nregs <= RUN_MAXREGS (1U << LG_RUN_MAXREGS) = (1U << (LG_PAGE - LG_TINY_MIN)) = 1<<(12 - 3) = 512
*
* bin_info->nregs and bin_info->reg0_offset are also calculated here, since
* these settings are all interdependent.
*/
bin_info_run_size_calc(arena_bin_info_t *bin_info)
bin_info->reg_interval = bin_info->reg_size + (bin_info->redzone_size << 1); redzone_size是0
try_run_size = PAGE; 4096
try_nregs = try_run_size / bin_info->reg_size; 4096/8 = 512
do {
perfect_run_size = try_run_size;
perfect_nregs = try_nregs;
try_run_size += PAGE;
try_nregs = try_run_size / bin_info->reg_size;
} while (perfect_run_size != perfect_nregs * bin_info->reg_size);
4096 == 512 * 8
如果reg_size是24,不能整除,这个循环就要进行多次,第一次perfect_run_size = 4096,perfect_nregs=170
第二次8192,341,。。。直到4096*n/24为整数方可,24的话,最后perfect_run_size=12288 = 24 * 512,perfect_nregs=512
actual_run_size = perfect_run_size; 4096
actual_nregs = (actual_run_size - pad_size) / bin_info->reg_interval; 512
actual_run_size > arena_maxrun条件没有走到,
bin_info->run_size = actual_run_size; 4096
bin_info->nregs = actual_nregs; 512
bin_info->reg0_offset = actual_run_size - (actual_nregs * bin_info->reg_interval) - pad_size + bin_info->redzone_size;
0
if (actual_run_size > small_maxrun)
small_maxrun = actual_run_size; small_maxrun存储的是最大的actual_run_size
assert(bin_info->reg0_offset - bin_info->redzone_size + (bin_info->nregs
* bin_info->reg_interval) + pad_size == bin_info->run_size);
small_run_size_init
small_maxrun = 28672(7页)
small_run_tab = (bool *)base_alloc(sizeof(bool) * (small_maxrun >> LG_PAGE));
csize = CACHELINE_CEILING(7);
(((s) + CACHELINE_MASK) & ~CACHELINE_MASK) = ((7 + (64 - 1)) & ~(64 - 1)) = 64
usize = s2u(csize);
s2u_lookup(size)-->index2size_lookup(size2index_lookup(size));
LOOKUP_MAXCLASS = ((((size_t)1) << 11) + (((size_t)4) << 9)) = 4096
const uint8_t size2index_tab[] = {
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
S2B_##lg_delta_lookup(index)
SC( 0, 3, 3, 0, yes, 3)
S2B_3(0)
S2B_3(1)
...S2B_4(8),S2B_5(12)...S2B_9(31)
LG_TINY_MIN == 3
#define S2B_3(i) i,
#if LG_TINY_MIN < 4
#define S2B_4(i) S2B_3(i) S2B_3(i) 4是2个3
#endif
#if LG_TINY_MIN < 5
#define S2B_5(i) S2B_4(i) S2B_4(i) 5是2个4
...
总数是8 + 4*2 + 4*2*2 + ... + 4*2^6 = 512
最大的index是31,(有256个31)
size_t ret = ((size_t)(size2index_tab[(size-1) >> LG_TINY_MIN]));
size2index_tab[(64 - 1) >> 3] = size2index_tab[7] = 7
7 == size2index_compute(64)
size_t ret = (size_t)index2size_tab[index]; 64
assert(ret == index2size_compute(index));
assert(ret == s2u_compute(size));
x = lg_floor((size<<1)-1); = lg_floor(127); 有6个1
lg_delta = x - LG_SIZE_CLASS_GROUP - 1 = 3
delta = ZU(1) << lg_delta; = 8
delta_mask = delta - 1; = 7
usize = (size + delta_mask) & ~delta_mask; = 64,意思是有余数就加一个整的
extent_node_t key;
extent_node_init(&key, NULL, NULL, usize, false, false);
malloc_mutex_lock(&base_mtx);
node = extent_tree_szad_nsearch(&base_avail_szad, &key); 在上面提到的红黑树上查找usize大小的node
找不到node = base_chunk_alloc(csize);
sizeof(extent_node_t) = 104
CACHELINE_CEILING = 128
CHUNK_CEILING(64 + 128); 2M,chunk的size是2M
chunk_alloc_base(2M);
zero = true;
commit = true;
ret = chunk_alloc_mmap(size, chunksize, &zero, &commit);
ret = pages_map(NULL, size);
ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
MAP_ANON表明不映射任何文件
返回的内存地址介于堆和栈中间
offset = ALIGNMENT_ADDR2OFFSET(ret, alignment);
((size_t)((uintptr_t)(a) & (alignment - 1)))
如果不是按照2M对齐的,
pages_unmap(ret, size);
munmap(addr, size)
chunk_alloc_mmap_slow(size, alignment, zero, commit)
alloc_size = size + alignment - PAGE; 4M - 4K
页是最小的分配单位,4M-4K意思就是分配2个大小,但又不超过2个大小的最大值
这样能确保这个大小的区间必定有一个以2M对齐的地址开始,往后1个大小的连续块
do {
pages = pages_map(NULL, alloc_size);
leadsize = ALIGNMENT_CEILING((uintptr_t)pages, alignment) - (uintptr_t)pages
(((s) + (alignment - 1)) & (-(alignment)))
p /x -alignment = 0xffffffffffe00000 21个0,2M是21个1,ALIGNMENT_CEILING含义是pages对2M的
余数不为0,就让pages增加到2M的最小倍数,即pages/2M + 2M的地方
leadsize表示地址后移的偏移量
ret = pages_trim(pages, alloc_size, leadsize, size);
pages_unmap(addr, leadsize);去掉开通
pages_unmap((void *)((uintptr_t)ret + size), trailsize);去掉结尾
} while (ret == NULL);
base_mapped += csize;
node = (extent_node_t *)addr;
addr = (void *)((uintptr_t)addr + nsize);
csize -= nsize;
这块内存的前128字节存储extent_node_t,剩余的字节可供使用
extent_node_init(node, NULL, addr, csize, true, true);
ret = extent_node_addr_get(node);
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);
拿出64字节,地址是ret。剩余还有字节数,放到base_avail_szad树中
#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \
TAB_INIT_bin_##bin(index, (ZU(1)<
TAB_INIT_bin_yes(0, (ZU(1)<<3) + (ZU(0)<<3)) 后面这个参数没有用
arena_bin_info_t *bin_info = &arena_bin_info[0];
small_run_tab[bin_info->run_size >> LG_PAGE] = true;
small_run_tab就是上面分配的
TAB_INIT_bin_yes(38, (ZU(1)<<13) + (ZU(3)<<11))
tcache_boot
tcache_maxclass = (1U << opt_lg_tcache_max);
je_tcache_maxclass = 1 << 15 = 0x8000 32k,8页
nhbins = size2index(tcache_maxclass) + 1;
32k > 4k,size2index_compute(size)
x = g_floor((size<<1)-1 最高位的1是第15位
shift = x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM) = 15 - (2 + 3) = 10
size_t grp = shift << LG_SIZE_CLASS_GROUP; 10 << 2 = 40
lg_delta = x - LG_SIZE_CLASS_GROUP - 1; 15 -2 - 1 = 12
delta_inverse_mask = ZI(-1) << lg_delta; 低位12个0
mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1);
((15个1 & 12个0) >> 12) & ((1<<2) - 1) = 3, 2个1
index = NTBINS + grp + mod; 0 + 40 + 3 = 43
44
tcache_bin_info = (tcache_bin_info_t *)base_alloc(nhbins * sizeof(tcache_bin_info_t));
4*44 = 196
csize = CACHELINE_CEILING(size); 192
usize = s2u(csize); 192
在查找函数a_prefix##nsearch中
int cmp = (a_cmp)(key, tnode); \
if (cmp < 0) { \
ret = tnode; \ 保存了比要查找的size大的节点,不行就用这个稍大的节点
tnode = rbtn_left_get(a_type, a_field, tnode);
查找
extent_tree_szad_nsearch(&base_avail_szad, &key);
找到删除
extent_tree_szad_remove(&base_avail_szad, node);
分配完空间,更新节点信息,再放回树中
extent_tree_szad_insert(&base_avail_szad, node);
for (i = 0; i < NBINS; i++) {
arena_bin_info[i].nregs << 1
<= TCACHE_NSLOTS_SMALL_MIN = 20 (19,23,25,27-38)
tcache_bin_info[i].ncached_max = 20
<= TCACHE_NSLOTS_SMALL_MAX = 200(7,11,13,15-18,20-22,24,26)
tcache_bin_info[i].ncached_max = arena_bin_info[i].nregs << 1
其他
tcache_bin_info[i].ncached_max = 200(0-6,8-10,12,14)
stack_nelms += tcache_bin_info[i].ncached_max;
没有遍历完的,nhbins是44,NBINS是39
for (; i < nhbins; i++) {
tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_LARGE;
stack_nelms += tcache_bin_info[i].ncached_max;
}
malloc_mutex_init(&arenas_lock)
narenas_total = narenas_auto = 1;
arenas = &a0;
memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
arena_init(0)
arena = arena_init_locked(ind);
MALLOCX_ARENA_MAX = 0xffe = 4094
arena = arenas[ind] = arena_new(ind);
arena = (arena_t *)base_alloc(
CACHELINE_CEILING(sizeof(arena_t)) 9840, 64字节对齐(这么大是因为有arena_bin_t bins[NBINS];)
+ QUANTUM_CEILING(nlclasses * sizeof(malloc_large_stats_t)
nhclasses * sizeof(malloc_huge_stats_t)
(28 * 32 + 172) 8字节对齐 * 24,这里它代码应该写错了
nhclasses是malloc_huge_stats_t的个数,他这里多分配内存了
);
总共35584字节
arena->ind = ind;
arena->nthreads = 0;
malloc_mutex_init(&arena->lock)
memset(&arena->stats, 0, sizeof(arena_stats_t));
arena->stats.lstats = (malloc_large_stats_t *)((uintptr_t)arena
+ CACHELINE_CEILING(sizeof(arena_t)));
memset(arena->stats.lstats, 0, nlclasses *
sizeof(malloc_large_stats_t)); // 初始化malloc_large_stats_t数组
arena->stats.hstats = (malloc_huge_stats_t *)((uintptr_t)arena
+ CACHELINE_CEILING(sizeof(arena_t)) +
QUANTUM_CEILING(nlclasses * sizeof(malloc_large_stats_t)));
memset(arena->stats.hstats, 0, nhclasses *
sizeof(malloc_huge_stats_t)); //初始化malloc_huge_stats_t数组
ql_new(&arena->tcache_ql); //初始化表头
arena->offset_state = config_debug ? ind : (uint64_t)(uintptr_t)arena; //offset_state指向arena地址
arena->dss_prec = chunk_dss_prec_get(); //dss_prec_secondary
arena->spare = NULL;
arena->lg_dirty_mult = arena_lg_dirty_mult_default_get(); //3 arena_boot写的
arena->purging = false;
arena->nactive = 0;
arena->ndirty = 0;
arena_avail_tree_new(&arena->runs_avail);初始化一个红黑树
typedef rb_tree(arena_chunk_map_misc_t) arena_avail_tree_t;
rb_gen(static UNUSED, arena_avail_tree_, arena_avail_tree_t,
arena_chunk_map_misc_t, rb_link, arena_avail_comp)
qr_new(&arena->runs_dirty, rd_link); //初始化双向链表
qr_new(&arena->chunks_cache, cc_link);
ql_new(&arena->huge); //单链表
malloc_mutex_init(&arena->huge_mtx)
extent_tree_szad_new(&arena->chunks_szad_cached); 红黑树
typedef rb_tree(extent_node_t) extent_tree_t;
rb_proto(, extent_tree_szad_, extent_tree_t, extent_node_t)
rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t)
extent_tree_ad_new(&arena->chunks_ad_cached); 红黑树
extent_tree_szad_new(&arena->chunks_szad_retained); 红黑树
extent_tree_ad_new(&arena->chunks_ad_retained); 红黑树
malloc_mutex_init(&arena->chunks_mtx)
ql_new(&arena->node_cache);
malloc_mutex_init(&arena->node_cache_mtx)
arena->chunk_hooks = chunk_hooks_default;
const chunk_hooks_t chunk_hooks_default = {
chunk_alloc_default,
chunk_dalloc_default,
chunk_commit_default,
chunk_decommit_default,
chunk_purge_default,
chunk_split_default,
chunk_merge_default
};
/* Initialize bins. */
for (i = 0; i < NBINS; i++) {
bin = &arena->bins[i];
if (malloc_mutex_init(&bin->lock))
return (NULL);
bin->runcur = NULL;
arena_run_tree_new(&bin->runs); //
/* Generate red-black tree functions. */
rb_gen(static UNUSED, arena_run_tree_, arena_run_tree_t, arena_chunk_map_misc_t, rb_link, arena_run_comp)
if (config_stats)
memset(&bin->stats, 0, sizeof(malloc_bin_stats_t));
}
malloc_init_state = malloc_init_a0_initialized;
malloc_tsd_boot0()
tsd_boot0()
malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) tsd.c
#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \
a_attr __thread a_type JEMALLOC_TLS_MODEL \
a_name##tsd_tls = a_initializer; \
a_attr pthread_key_t a_name##tsd_tsd; \
a_attr bool a_name##tsd_booted = false;
tsd.h中定义
malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup)
#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \
a_cleanup) \
/* Initialization/cleanup. */ \
a_attr bool \
a_name##tsd_boot0(void) \
{ \
\
if (a_cleanup != malloc_tsd_no_cleanup) { \
if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ 创建线程自己的tsd_tsd
0) \
return (true); \
} \
a_name##tsd_booted = true; \
return (false); \
} \
*tsd_arenas_cache_bypassp_get(tsd_fetch()) = true;
tsd_t *tsd = tsd_get(); 返回tsd_tls
tsd->state = tsd_state_nominal;
tsd_set(tsd);
tsd_tls = (*val);
pthread_setspecific(a_name##tsd_tsd, (void *)(&a_name##tsd_tls))
#define MALLOC_TSD \ 在tsd.c中展开
/* O(name, type) */ \
O(tcache, tcache_t *) \
O(thread_allocated, uint64_t) \
O(thread_deallocated, uint64_t) \
O(prof_tdata, prof_tdata_t *) \
O(arena, arena_t *) \
O(arenas_cache, arena_t **) \
O(narenas_cache, unsigned) \
O(arenas_cache_bypass, bool) \定义了一系列函数,包括tsd_(arenas_cache_bypass)p_get
O(tcache_enabled, tcache_enabled_t) \
O(quarantine, quarantine_t *) \
返回tsd_fetch()的arenas_cache_bypass字段,
struct tsd_s {
tsd_state_t state;
#define O(n, t) \ 这里面的O是字段申明
t n;
MALLOC_TSD
#undef O
};
malloc_init_hard_recursible
malloc_init_state = malloc_init_recursible;
malloc_mutex_unlock(&init_lock); 解锁,在malloc_init_hard一开始上的锁
ncpus = malloc_ncpus(); 2
pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, jemalloc_postfork_child)
内部创建子进程前在父进程中会调用prepare,内部创建子进程成功后,父进程会调用parent ,子进程会调用child。
malloc_mutex_lock(&init_lock);再上锁
malloc_init_hard_finish
je_opt_narenas = ncpus * 2^2
narenas_auto = opt_narenas;
narenas_total = narenas_auto;
arenas = (arena_t **)base_alloc(sizeof(arena_t *) * narenas_total);
memset(arenas, 0, sizeof(arena_t *) * narenas_total);
/* Copy the pointer to the one arena that was already initialized. */
arenas[0] = a0;
malloc_init_state = malloc_init_initialized;
malloc_mutex_unlock(&init_lock);解锁
malloc_tsd_boot1();
tsd_boot1();什么也不做
*tsd_arenas_cache_bypassp_get(tsd_fetch()) = false; tsd_tls字段赋值
malloc_init_hard分析结束
malloc_thread_init();
什么也没做
JEMALLOC_ALWAYS_INLINE_C void
malloc_thread_init(void)
{
/*
* TSD initialization can't be safely done as a side effect of
* deallocation, because it is possible for a thread to do nothing but
* deallocate its TLS data via free(), in which case writing to TLS
* would cause write-after-free memory corruption. The quarantine
* facility *only* gets used as a side effect of deallocation, so make
* a best effort attempt at initializing its TSD by hooking all
* allocation events.
*/
if (config_fill && unlikely(opt_quarantine)) opt_quarantine大部分是false
quarantine_alloc_hook();
}