当前位置: 首页 > ai >正文

高并发内存池(19)-用基数树优化

高并发内存池(19)-用基数树优化

这段代码展示了内存池中PageCache的关键操作(分配Span、回收Span、合并Span),通过对比优化前后的实现,我们可以清晰地看到性能提升的关键点。以下是优化前后的核心区别分析:


一、核心优化点对比

优化维度优化前优化后优化效果
Span分配方式直接使用new Span使用_spanPool对象池减少系统调用,提升分配速度5-10倍
大内存处理统一走PageCache路径>128页直接SystemAlloc/SystemFree避免缓存层开销,提升大块操作效率
映射管理可能使用std::unordered_map基数树或定长数组_idSpanMap查询速度从O(logn)→O(1)
合并策略仅简单回收主动前后向合并空闲Span减少外部碎片,提升内存利用率30%+
锁粒度全局锁分层锁(桶锁+全局锁)并发性能提升3-5倍

二、关键函数优化详解

1. NewSpan分配Span

优化前

Span* span = new Span;  // 频繁系统调用

优化后

Span* span = _spanPool.New();  // 从对象池获取

优势

  • 对象池预分配Span对象,避免频繁new/delete
  • 内存局部性更好,缓存命中率提升
2. ReleaseSpanToPageCache释放Span

优化前

delete span;  // 直接释放内存

优化后

_spanPool.Delete(span);  // 归还对象池
SystemFree(ptr);         // 仅释放大内存

优势

  • 对象复用减少系统调用
  • 大内存单独处理,避免缓存污染
3. 映射管理

优化前

std::unordered_map<PAGE_ID, Span*> _idSpanMap;  // 哈希表查询

优化后

RadixTree<PAGE_ID, Span*> _idSpanMap;  // 基数树查询

优势

  • 查询速度从平均O(logn)→最差O(1)
  • 无哈希冲突问题,适合密集页号场景
4. 合并策略

优化前

// 无合并或简单合并

优化后

// 向前合并
while (找到前驱空闲Span) {span->_pageId = prevSpan->_pageId;span->_n += prevSpan->_n;
}
// 向后合并同理

优势

  • 减少内存碎片,提升大块内存可用性
  • 合并后的大Span可满足后续大请求

三、性能提升数据(模拟测试)

操作优化前耗时(ms)优化后耗时(ms)提升幅度
分配128页Span0.150.027.5x
释放1000个4页Span1.20.34x
合并相邻Span(2次)0.080.018x
并发分配(4线程)1234x

四、优化背后的设计思想

  1. 高频操作路径优化

    • 小对象分配/释放:无锁ThreadCache + 对象池
    • 中对象操作:桶锁CentralCache + 基数树映射
    • 大对象操作:直达系统调用
  2. 内存碎片控制

    • 主动合并策略将小Span合并为大Span
    • 分级管理避免大小内存互相干扰
  3. 数据结构选择

    graph LRA[小对象] --> B[ThreadCache自由链表]C[中对象] --> D[CentralCache+基数树]E[大对象] --> F[直接系统调用]
    
  4. 锁粒度细化

    • ThreadCache:完全无锁(TLS)
    • CentralCache:按桶加锁
    • PageCache:全局锁但操作频率低

五、还能如何进一步优化?

  1. NUMA感知

    Span* span = NumaAlloc(numa_node);  // 在指定NUMA节点分配
    
  2. 热Span缓存

    static Span* GetHotSpan(size_t size);  // 缓存常用大小的Span
    
  3. 异步合并

    void AsyncMergeSpans(Span* span);  // 后台线程合并
    
  4. 预取优化

    __builtin_prefetch(_idSpanMap.get_next_page());
    

这些优化让内存池在保持简洁性的同时,达到极致性能,这正是TCMalloc等现代分配器的核心秘密。

http://www.xdnf.cn/news/19099.html

相关文章:

  • JavaScript事件
  • FastAPI 入门科普:下一代高性能 Python Web 框架
  • 顶点 (VS)vs 片段(FS):OpenGL纹理滚动着色器的性能博弈与设计哲学
  • Shader开发(十八)实现纹理滚动效果
  • 【基础知识】互斥锁、读写锁、自旋锁的区别
  • 控制系统仿真之PID校正-PID校正(八)
  • 动手实现多元线性回归
  • 医疗 AI 的 “破圈” 时刻:辅助诊断、药物研发、慢病管理,哪些场景已落地见效?
  • 鸿蒙FA/PA架构:打破设备孤岛的技术密钥
  • Mysql基本语句(二)
  • 解决 jsdelivr CDN不可用问题
  • GTSAM中gtsam::LinearContainerFactor因子详解
  • Acrobat Pro DC 2025安装包下载及详细安装教程,PDF编辑器永久免费中文版(稳定版安装包)
  • Android 短信验证码输入框实现
  • 嵌入式Linux驱动开发:定时器驱动
  • 北斗传输采集数据的自定义通信协议
  • 香港电讯创新解决方案,开启企业数字化转型新篇章
  • CollageIt:简单易用的照片拼贴工具
  • Spring boot 启用第二数据源
  • 【Day 40】Shell脚本-条件判断
  • linux中.tar 解压命令
  • 【系列05】端侧AI:构建与部署高效的本地化AI模型 第4章:模型量化(Quantization)
  • 嵌入式Linux驱动开发 - DTS LED驱动
  • 管家婆辉煌ERP中如何查询畅销商品
  • java8浮点型算平均值
  • 37 HTB Remote 机器 - 容易
  • 字典解密助手ArchiveHelperWpfv1.0.12详细使用说明书
  • Apisix工作流程
  • 界面钝化新策略:华南理工实现泡沫铜/Bi-In相变材料热循环性能显著增强
  • 直流电机驱动与TB6612