Page 501 - 《软件学报》2024年第4期
P. 501

欧阳湘臻 等: 榫卯: 一种可组合的定制化内存分配框架                                                     2079


                    (3) 可移植性更好. 榫卯框架基于标准          C  实现, 在一些只允许    C  编程的场合也能使用, 同时框架本身无外部库
                 依赖, 所有代码都对开发者都是可见的.
                    (4) 用户代码简洁性更好. 榫卯框架将实现的复杂性尽可能转移到框架本身的实现当中, 而呈现给用户的接口
                 是相当精简和直观的. 用户只需要数十行代码就能组合出一个复杂结构的内存分配器. 同时, 榫卯框架允许使用一
                 种抽象的模型语言描述分配器的架构.
                    为了说明榫卯框架的组合性和定制性, 本文给出了使用榫卯框架快速定制出的                          3  种针对不同应用场景的动态
                 内存分配器的实例, 分别为针对多核嵌入式实时系统优化的                   tlsfcc; 针对异构多核系统优化的       hslab; 针对高并发和
                 延迟敏感场景优化的        wfslab. 本文通过运行内存分配器基准测试, 收集相关性能统计信息, 从平均执行时间, 内存
                 占用, 最差情况内存请求延迟         3  个角度评估这    3  种内存分配器. 为了证明榫卯框架的可移植性, 实验分别在                 8  核
                 16  线程的  x86/64 AMD Ryzen 3700x  平台和  8  核异构  aarch64 Qualcomm Snapdragon 888+嵌入式平台进行, 参与实
                 验对比的通用或专用内存分配器包括:
                                                                  [17]
                    glibcmalloc (https://www.gnu.org/software/libc/sources.html), tlsf , tcmalloc (https://github.com/gperftools/gperftools),
                 jemalloc (https://github.com/jemalloc/jemalloc), Hoard [18] , tbbmalloc [19] , mimalloc/smimalloc [20] , snmalloc [21] , Scudo
                 (https://github.com/llvm/llvm-project/tree/main/compiler-rt/lib/scudo), mng (https://github.com/richfelker/mallocng-
                 draft), Diehard [22] .
                    实验结果显示使用榫卯框架实现的             3  种内存分配器实例满足其应用场景要求的性能优化目标, 从而证明了榫
                 卯框架的有效性.
                    本文第   1  节介绍内存分配器与内存分配框架的相关研究. 第                2  节介绍榫卯内存分配框架的设计与实现细节.
                 第  3  节介绍使用榫卯框架构建专用内存分配器的             3  个实例. 第  4  节介绍实验设置并给出实验结果和对比分析. 第
                 5  节总结全文.
                  1   相关工作

                    内存分配器作为系统的关键组件, 其相关算法与高性能实现已有大量的研究, 这些研究主要集中在优化内存
                 分配器执行时间, 内存利用率以及容错性. 本节主要介绍通用内存分配器, 专用内存分配器以及内存分配框架的相
                 关工作.
                  1.1   通用内存分配器
                    随着多核处理器得到普及, 为了解决线程安全和多核可扩展性问题, 分配器必须使用合适的同步方式处理共
                 享数据的并发访问. 本文按照通用内存分配器使用的同步方式, 将这些内存分配器分为基于锁的内存分配器与无
                 锁内存分配器两大类.
                    基于锁的通用内存分配器包括           ptmalloc, jemalloc, tcmalloc, Hoard [18] . ptmalloc 是  GNU C  库默认的分配器, 下
                 文中称为   glibc malloc. 它是一种分割-合并式分配器, 使用带标记的          chunk  作为分割-合并的基本单位. glibc malloc
                 使用分级管理策略维护        chunk, 依据  chunk  大小实行不同的分配策略. 同时, glibc 分配器通过将锁的竞争分散到不
                 同的共享数据结构       arena 中以提供多核可扩展性. jemalloc 是     FreeBSD  使用的内存分配器, 它是一种       slab  式的分
                 配器. 连续的内存被划分为        run, 每个  run  会被划分成特定大小的小内存块, 小内存块之间不会分割或合并, 每个
                 run  通过  bitmap  标记内存的使用情况. jemalloc 的多核同步策略与       glibc 相似, 它使用  4  倍于最大核心数的     arena.
                 线程被指派到一组       arena 中, 以降低对同一   arena 的并发竞争. tcmalloc 是  Google Chrome 浏览器中使用的内存分
                 配器, 它通过线程本地分配缓存          thread cache 与中心式的  central cache 来管理空闲内存. 同时, 为了防止单一线程
                 持有大量空闲内存, tcmalloc 实现了      thread cache 窃取机制. Hoard  为了缓解并发瓶颈, 将用户堆分为全局堆和每
                 CPU  核心堆两种, 以分担并发压力. 另外, Hoard       通过确保相同      CPU  核心尽可能使用相同      cache 行来降低跨    CPU
                 核心的   cache  行并发访问对性能的影响, 以一定内存消耗为代价提升                 CPU  访存性能. 在使用的同步技术方面,
                 glibc malloc, jemalloc, tcmalloc 和  Hoard  都使用锁来保证线程安全性, 其中  glibc malloc, jemalloc 使用  POSIX  互斥
   496   497   498   499   500   501   502   503   504   505   506