ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux内存管理(四):Jemalloc

2021-07-04 12:31:35  阅读:577  来源: 互联网

标签:arena bin run 内存 Linux Jemalloc 分配 size


1. Jemalloc简介

    jemalloc 是由 Jason Evans 在 FreeBSD 项目中引入的新一代内存分配器。它是一个通用的 malloc 实现,侧重于减少内存碎片和提升高并发场景下内存的分配效率,其目标是能够替代 malloc。jemalloc 应用十分广泛,在 Firefox、Redis、Rust、Netty 等出名的产品或者编程语言中都有大量使用。具体细节可以参考 Jason Evans 发表的论文 《A Scalable Concurrent malloc Implementation for FreeBSD》。

    jemalloc 借鉴了 tcmalloc 优秀的设计思路,所以在架构设计方面两者有很多相似之处,同样都包含 thread cache 的特性。但是 jemalloc 在设计上比 ptmalloc 和 tcmalloc 都要复杂,jemalloc 将内存分配粒度划分为 Small、Large、Huge 三个分类,并记录了很多 meta 数据,所以在空间占用上要略多于 tcmalloc,不过在大内存分配的场景,jemalloc 的内存碎片要少于 tcmalloc。tcmalloc 内部采用红黑树管理内存块和分页,Huge 对象通过红黑树查找索引数据可以控制在指数级时间。

2. 基础知识

2.1 size_class

    每个 size_class 代表 jemalloc 分配的内存大小,共有 NSIZES(232)个小类(如果用户申请的大小位于两个小类之间,会取较大的,比如申请14字节,位于8和16字节之间,按16字节分配),分为2大类:

  • small_class小内存 :

    对于64位机器来说,通常区间是 [8, 14kb],常见的有 8, 16, 32, 48, 64, …, 2kb, 4kb, 8kb,注意为了减少内存碎片并不都是2的次幂,比如如果没有48字节,那当申请33字节时,分配64字节显然会造成约50%的内存碎片

  • large_class大内存:

    对于64位机器来说,通常区间是 [16kb, 7EiB],从 4 * page_size 开始,常见的比如 16kb, 32kb, …, 1mb, 2mb, 4mb,最大是 $2^{62}+3^{60}$

  • size_index (size 索引:

    size 位于 size_class 中的索引号,区间为 [0,231],比如8字节则为0,14字节(按16计算)为1,4kb字节为28,当 size 是 small_class 时,size_index 也称作 binind

2.2 arena

    arena 是 jemalloc 最重要的部分,内存由一定数量的 arenas 负责管理。每个用户线程都会被绑定到一个 arena 上,线程采用 round-robin 轮询的方式选择可用的 arena 进行内存分配,为了减少线程之间的锁竞争,默认每个 CPU 会分配 4 个 arena。

    每个arena内都会包含对应的管理信息,记录该arena的分配情况。arena都有专属的chunks, 每个chunk的头部都记录了chunk的分配信息。在使用某一个chunk的时候,会把它分割成很多个run,并记录到bin中。不同size的class对应着不同的bin,在bin里,都会有一个红黑树来维护空闲的run,并且在run里,使用了bitmap来记录了分配状态。此外,每个arena里面维护一组按地址排列的可获得的run的红黑树。

struct arena_s {
    ...
    arena_chunk_tree_t  chunks_dirty;  // 当前arena管理的dirty chunks

    arena_chunk_t *spare;     // arena缓存的最近释放的chunk, 每个arena一个spare chunk

    size_t nactive;           // 当前arena中正在使用的page数.

    size_t ndirty;            // 当前arana中未使用的dirty page数

    size_t npurgatory;        // 需要清理的page的大概数目
 
    /* 当前arena可获得的runs构成的红黑树,红黑树按大小/地址顺序进行排列。 分配run时采用first-best-fit策略 */
    arena_avail_tree_t runs_avail;

    arena_bin_t bins[NBINS];  // bins储存不同大小size的内存区域
};

2.3 bin

    在arena中, 不同bin管理不同size大小的run,在任意时刻, bin中会针对当前size保存一个run用于内存分配。

struct arena_bin_s {
    malloc_mutex_t  lock;    // 作用域当前数据结构的锁

    arena_run_t *runcur;     // 当前正在使用的run

    /* 
     * 可用的run构成的红黑树, 主要用于runcur用完的时候。在查找可用run时, 
     * 为保证对象紧凑分布,尽量从低地址开始查找,减少快要空闲的chunk的数量。
     */
    arena_run_tree_t runs;

    malloc_bin_stats_t stats;  // 用于bin统计
};

2.4 run 

    每个bin在实际上是通过对它对应的正在运行的Run进行操作来进行分配的,一个run实际上就是chunk里的一块区域,大小是page的整数倍,在run的最开头会存储着这个run的信息,比如还有多少个块可供分配。下一块可分配区域的索引。

struct arena_run_s {

    arena_bin_t *bin;      // 所属的bin 

    uint32_t    nextind;  // 下一块可分配区域的索引

    unsigned    nfree;    // 当前run中空闲块数目
};

  // todo

3. 内存分配

  // todo

4. 内存释放

// todo

5. 内存再分配

// todo

6. 内存GC

// todo

标签:arena,bin,run,内存,Linux,Jemalloc,分配,size
来源: https://blog.csdn.net/MOU_IT/article/details/118460045

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有