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

2090                                                       软件学报  2024  年第  35  卷第  4  期


                 一个使用内存块头部魔数检验的延迟释放层               delayed(chk_sum=magic, node_xor=1, delayed_size=64KB, err_handle=
                 fatal), 用于检测重复释放和释放后使用行为, 该层级使用线程私有链表管理延迟释放的内存, 最大管理的内存大小
                 为  64 KB, 按  FIFO  顺序换出. 链表节点记录的指针和内存块大小使用异或编码, 以一定概率避免被用户非法内存
                 修改覆盖. 同时, 该层使用致命错误处理策略, 一旦检测出错误立刻终止程序. tlsfccsd                  则同时增加了上述两个层级.
                  4.2   基准测试集与评价指标
                    由于内存分配器的设计通常是执行时间与内存占用的取舍, 评估通用内存分配器通常使用平均执行时间和内
                 存利用率两个性能指标. 不过, 软实时系统应用动态内存分配器也较为常见, 如监控系统与移动通信基站软件. 在
                 这些系统中, 内存分配器不仅要求平均执行时间低, 内存利用率高, 还要求有确定的最差情况内存请求延迟, 以避
                 免实时任务执行超时. 因此本文还将对分配器的最差内存请求延迟进行评估.
                    本文通过运行基准测试对比内存分配器的平均执行时间与内存利用率, 实验中使用的基准测试主要来自开源
                 库  mimalloc-bench, 其中包含多组实际应用程序基准测试程序与不同场景的压力测试负载. 本文用于对比的基准
                 测试负载有:
                    (1) cfrac: 单线程科学计算应用, 用于计算整数的质因数分解, 存在大量的小内存申请与释放.
                    (2) barnes [41] : 来自  SPLASH-2  并行计算基准测试集, 用于模拟  163 840  个粒子的引力.
                    (3) espresso [42] : 单线程可编程逻辑数组分析器, 存在一些     realloc 内存分配场景.
                                                                          6
                    (4) redis: 内存数据库服务应用, 使用最大硬件线程并发连接数进行               10 次插入   10  个元素并且请求    10  个元素.
                    (5) lean [20] : 调用  lean  编译器编译  lean  标准库.
                                                                                              6
                    (6) cxqueue [43] : 并发队列数据结构的负载, 分别使用    msqueue [28] , wfqueue [30] 与  crtqueue [44] 进行  10 次并发入队
                 和出队操作, 每批入队      16 384  个节点.
                    (7) larson  [45] : 模拟真实服务器上观察到的大量线程的并发申请和释放工作负载, 其中许多动态内存对象并非
                 由申请线程释放.
                    (8) cscratch [18] : 主要用于测量被动  cache 伪共享  (false-sharing) 的微基准测试, 其中线程分配小对象并交给其
                 他线程访问对象, 如果不同线程拥有的对象处于一个                 cache 行则会导致   cache 行竞争.
                    (9) xmalloc-test: 该微基准测试使用  100  个分配线程和   100  个释放线程进行内存请求与释放.
                    (10) rptest: 来自  rpmalloc 的测试程序, 存在大量内存的并发申请和释放, 部分内存请求使用对齐分配.
                    (11) glibc-simple/glibc-thread: glibc malloc 使用的基准测试程序, 前者为单线程, 后者为多线程.
                    (12) sh6bench/sh8bench: 来自  SmartHeap  的基准测试, 其释放模式有一部分是后进先出顺序, 一部分则是先进
                 先出顺序释放. 其中还有一部分内存是由非申请线程释放的.
                    (13) alloc-test: 内存分配压力测试, 随机分配大小服从帕累托分布.
                    (14) mstress [20] : mimalloc 中用于模拟真实服务器释放模式的负载, 分配对象会在多个线程间迁移, 其中线程在
                 结束前不会将所有对象释放, 换言之, 有一些对象会在线程结束后依然存活.
                    此外, 本文使用一种微基准测试          wcet_test 来测量最差情况内存请求延时. 参与实验对比的所有内存分配器在
                 单线程的情况下的最差内存请求延迟理论上都是有界的. 然而, 在多核并发竞争过程中由于部分分配器使用了非
                 公平自旋锁或是无锁同步技术, 这些同步方式不能保证线程无饥饿, 因此并发场景下理论最差情况执行时间是不
                 确定的. 从实际系统的应用场景角度来看, 等待锁的过程中也不可避免会触发上下文切换, 调度和核心迁移, 这些
                 操作系统调度行为会对内存请求延迟产生不利影响. 评估各分配器的最差内存请求执行时间需要测量内存分配器
                 线程间并发竞争最紧张的情况下的执行时间, 这在大多数实际应用中都不会有这种极端的分配释放场景. 即使是
                 存在大量小对象分配与释放的无等待/无锁数据结构测试负载                     cxqueue, 其最大吞吐率也仅为数百万请求每秒. 为
                 了模拟这种极端情况下的分配释放, 本文综合               xmalloc-test, larson  和  cscratch  测试基准中的设计思想, 设计了一种
                 并发压力微基准测试, 该微基准测试以最大硬件线程数执行, 每个线程执行一千万次相同大小阶的分配与释放. 每
                 个线程的申请释放由多个批次构成, 每批次负载申请内存大小是不对称的, 单个线程最多一次性执行总大小                                  8 MB
   507   508   509   510   511   512   513   514   515   516   517