jemalloc源码结构分析(一):内存申请处理过程

一、5种malloc方法

1)tcache_alloc_small

2)arena_malloc_small

3)tcache_alloc_large

4)arena_malloc_large

5)huge_malloc

//written in jemalloc_internal.h file
imalloct(size_t size, bool try_tcache, arena_t *arena)
{
        assert(size != 0);

        if (size <= arena_maxclass)
                return (arena_malloc(arena, size, false, try_tcache));
        else
                return (huge_malloc(size, false, huge_dss_prec_get(arena)));
}

JEMALLOC_ALWAYS_INLINE void *
imalloc(size_t size)
{

        return (imalloct(size, true, NULL));
}
//written in arena.h
JEMALLOC_ALWAYS_INLINE void *
arena_malloc(arena_t *arena, size_t size, bool zero, bool try_tcache)
{
        tcache_t *tcache;

        assert(size != 0);
        assert(size <= arena_maxclass);

        if (size <= SMALL_MAXCLASS) {
                if (try_tcache && (tcache = tcache_get(true)) != NULL)
                        return (tcache_alloc_small(tcache, size, zero));
                else {
                        return (arena_malloc_small(choose_arena(arena), size,
                            zero));
                }
        } else {
                /*
                 * Initialize tcache after checking size in order to avoid
                 * infinite recursion during tcache initialization.
                 */
                if (try_tcache && size <= tcache_maxclass && (tcache =
                    tcache_get(true)) != NULL)
                        return (tcache_alloc_large(tcache, size, zero));
                else {
                        return (arena_malloc_large(choose_arena(arena), size,
                            zero));
                }
        }
}

 二、malloc时选择arena的机制

1)先用arenas_tsd_get获得线程绑定变量arena;

2)如果1)获得值为null,则扫描arenas数组,找到threads number为0或者最小的未卸载的arena;

3)如果2)中扫描发现存在null插槽,则需要调用arenas_extend进行初始化null插槽;

4)调用arenas_tsd_set设置线程绑定比变量arena。

//详细见jemalloc.c中函数
arena_t *choose_arena_hard(void)

三、arenas_extend处理过程 

在choose_arena处理过程中,找到一个null空arena后,需要对该arena做初始化,即调用arenas_extend函数,它的处理过程如下:

1)base_alloc arena_t对象;

2)arena_new arena_t对象;

arena_t *arenas_extend(unsigned ind)
{
        arena_t *ret;

        ret = (arena_t *)base_alloc(sizeof(arena_t));
        if (ret != NULL && arena_new(ret, ind) == false) {
                arenas[ind] = ret;
                return (ret);
        }
        /* Only reached if there is an OOM error. */

        /*
         * OOM here is quite inconvenient to propagate, since dealing with it
         * would require a check for failure in the fast path.  Instead, punt
         * by using arenas[0].  In practice, this is an extremely unlikely
         * failure.
         */
        malloc_write("<jemalloc>: Error initializing arena
");
        if (opt_abort)
                abort();

        return (arenas[0]);
}

四、base_alloc处理过程

1)数据对齐CACHELINE_CEILING,即64位对齐(8字节);

2)调用base_pages_alloc申请足够内存,从而调用chunk_alloc申请chunk对象;

3)chunk_alloc过程:如果采用dss优先的申请方式,则尝试sbrk这种方式申请,再尝试mmap这种方式;反之,则反序。 

chunk_alloc(size_t size, size_t alignment, bool base, bool *zero,
    dss_prec_t dss_prec)
{
        void *ret;

        assert(size != 0);
        assert((size & chunksize_mask) == 0);
        assert(alignment != 0);
        assert((alignment & chunksize_mask) == 0);

        /* "primary" dss. */
        if (config_dss && dss_prec == dss_prec_primary) {
                if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size,
                    alignment, base, zero)) != NULL)
                        goto label_return;
                if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL)
                        goto label_return;
        }
        /* mmap. */
        if ((ret = chunk_recycle(&chunks_szad_mmap, &chunks_ad_mmap, size,
            alignment, base, zero)) != NULL)
                goto label_return;
        if ((ret = chunk_alloc_mmap(size, alignment, zero)) != NULL)
                goto label_return;
        /* "secondary" dss. */
        if (config_dss && dss_prec == dss_prec_secondary) {
                if ((ret = chunk_recycle(&chunks_szad_dss, &chunks_ad_dss, size,
                    alignment, base, zero)) != NULL)
                        goto label_return;
                if ((ret = chunk_alloc_dss(size, alignment, zero)) != NULL)
                        goto label_return;
        }
        /* All strategies for allocation failed. */
        ret = NULL;
label_return:
        if (ret != NULL) {
                if (config_ivsalloc && base == false) {
                        if (rtree_set(chunks_rtree, (uintptr_t)ret, 1)) {
                                chunk_dealloc(ret, size, true);
                                return (NULL);
                        }
                }
                if (config_stats || config_prof) {
                        bool gdump;
                        malloc_mutex_lock(&chunks_mtx);
                        if (config_stats)
                                stats_chunks.nchunks += (size / chunksize);
                        stats_chunks.curchunks += (size / chunksize);
                        if (stats_chunks.curchunks > stats_chunks.highchunks) {
                                stats_chunks.highchunks =
                                    stats_chunks.curchunks;
                                if (config_prof)
                                        gdump = true;
                        } else if (config_prof)
                                gdump = false;
                        malloc_mutex_unlock(&chunks_mtx);
                        if (config_prof && opt_prof && opt_prof_gdump && gdump)
                                prof_gdump();
                }
                if (config_valgrind)
                        VALGRIND_MAKE_MEM_UNDEFINED(ret, size);
        }
                                                                                                                                    1
       return ret;
}
原文地址:https://www.cnblogs.com/feika/p/3675711.html