Jemalloc 初始化

这是redis对jemalloc的配置
./configure --with-lg-quantum=3 --with-jemalloc-prefix=je_ \
    --enable-cc-silence CFLAGS="-std=gnu99 -Wall -pipe -g -O0 -funroll-loops " LDFLAGS=""
    
imalloc_body(size_t size, tsd_t **tsd, size_t *usize)
if (unlikely(malloc_init()))
    return (NULL); 告诉gcc,malloc_init一般情况下返回false,不会返回true

JEMALLOC_ALWAYS_INLINE_C bool
malloc_init(void)
{
    if (unlikely(!malloc_initialized()) && malloc_init_hard())
        return (true); malloc_initialized大部分情况返回true,造成unlikely(!malloc_initialized())短路,就不用调用malloc_init_hard
    malloc_thread_init();

    return (false);
}

malloc_init_hard是在何时第一次调用呢
(gdb) bt
#0  malloc_init_hard () at src/jemalloc.c:1317
#1  0x00000000005dbf09 in malloc_init () at src/jemalloc.c:285
#2  jemalloc_constructor () at src/jemalloc.c:2515
#3  0x00000000006ce75d in __libc_csu_init ()
#4  0x00007ffff730ee55 in __libc_start_main (main=0x42e4b8
, argc=1, argv=0x7fffffffe408, init=0x6ce710 <__libc_csu_init>,
    fini=, rtld_fini=, stack_end=0x7fffffffe3f8) at libc-start.c:246
#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 ) at src/mutex.c:73
            #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
, argc=1, argv=0x7fffffffe408, init=0x6ce710 <__libc_csu_init>,
            fini=, rtld_fini=, stack_end=0x7fffffffe3f8) at libc-start.c:246
            #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)<                     SC(  0,      3,        3,      0, yes,  3)
                        (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)<                 SC(  0,      3,        3,      0, yes,  3)
                    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)<                 SC(  0,      3,        3,      0, yes,  3)
                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();
}



你可能感兴趣的:(Jemalloc 初始化)