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

智能高效内存分配器测试报告

一、项目背景

  1. 这个项目是为了学习和实现一个高性能、特别是高并发场景下的内存分配器。这个项目是基于谷歌开源项目tcmalloc(Thread-Caching Malloc)实现的。tcmalloc 的核心目标就是替代系统默认的 malloc/free,在多线程环境下提供更高效的内存管理。
  2. C/C++的malloc虽然通用,但在高并发环境下,频繁申请和释放内存会引起剧烈锁竞争,进而造成性能瓶颈。
  3. 理解tcmalloc这个项目,不仅是深入 C++ 高性能编程、提升技术深度的绝佳途径,也是巩固C++学习的重要方式。

二、项目功能

项目介绍

采取三层结构:thread_cache-central_cache-page_cache。当一个线程需要申请内存时,先向thread cache进行申请,thread cache没有内存,转而向central cache进行申请,central cache没有内存,转而向page cache进行申请,page cache没有内存,会直接在堆上进行开辟。

​ 在进行归还内存时,不会直接释放掉,直接释放掉下次申请还要再进行上面的流程。对thread cache增加自由链表的结构,每次用完释放后,直接将其链入thread cache的自由链表中,待自由链表长度过长或占用内存过大,我们在统一进行回收合并,这样也能解决外碎片问题。

​ 这三层结构主要解决小于和等于256KB大小的内存申请和释放问题,对于申请和释放大于256KB的内存块,直接向page cache进行申请和释放。

​ **thread cache:**对于小块内存进行管理,这个是每个线程独有的,这里不存在线程安全问题,不用进行加锁,每个线程独享一个cache。

​ **central cache:**中心缓存,所有线程共享的,thread cache按需从里面申请内存,会在合适时候对thread cache进行回收,以达到内存调度。central cache这里会存在内存竞争的问题,所以需要加锁。

​ **page cache:**是以页为单位进行存储和分配的,central cache向其申请对象时,page cache会给出若干页,进行切割定长内存小块分配给central cache。当若干页进行回收后,会进行合并,解决了内存碎片问题(外碎片)

项目目标

  1. 高性能: 绝大多数小内存分配在 Thread Cache 无锁完成,大幅提升并发性能。
  2. 低锁竞争: 通过线程私有缓存和批量操作,将全局锁竞争降到最低(主要在 Central Cache 的桶锁)。
  3. 碎片控制: Page Cache 的合并机制有效缓解了外部碎片问题。

三、测试计划

单元测试

**一般测试:**测试是否能正常工作
void Test_ConcurrentAlloc1()
{int* p1 = (int*)ConcurrentAlloc(6); //maxsize:2 allocnum:1 size:0int* p2 = (int*)ConcurrentAlloc(7); //3 2 1int* p3 = (int*)ConcurrentAlloc(8); //3   0int* p4 = (int*)ConcurrentAlloc(1); //4 3 2int* p5 = (int*)ConcurrentAlloc(1); //4   1int* p6 = (int*)ConcurrentAlloc(1); //4   0int* p7 = (int*)ConcurrentAlloc(1); //5 4 3*p1 = 10;*p2 = 20;*p3 = 30;*p4 = 40;cout << p1 << ": " << *p1 << endl;cout << p2 << ": " << *p2 << endl;cout << p3 << ": " << *p3 << endl;cout << p4 << ": " << *p4 << endl;ConcurrentFree(p1); //maxsize:5 size:4 span._usecount:10ConcurrentFree(p2); //5 0 5ConcurrentFree(p3); //5 1 5ConcurrentFree(p4); //5 2 5ConcurrentFree(p5); //5 3 5ConcurrentFree(p6); //5 4 5ConcurrentFree(p7); //5 0 0 
}

运行结果:

在这里插入图片描述

特殊测试:是否可以分配大块内存
void Test_BigAlloc()
{int *p1 = (int *)ConcurrentAlloc(MAX_BYTES + 100);int *p2 = (int *)ConcurrentAlloc(NPAGES << PAGE_SHIFT);*p1 = 10;*p2 = 20;cout << p1 << ": " << *p1 << endl;cout << p2 << ": " << *p2 << endl;ConcurrentFree(p1);ConcurrentFree(p2);
}

测试结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

基准测试

// ntimes 一轮申请和释放内存的次数
// rounds 轮次
void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds)
{std::vector<std::thread> vthread(nworks);std::atomic<size_t> malloc_costtime = 0;std::atomic<size_t> free_costtime = 0;for (size_t k = 0; k < nworks; ++k){vthread[k] = std::thread([&, k]() {std::vector<void*> v;v.reserve(ntimes);for (size_t j = 0; j < rounds; ++j){size_t begin1 = clock();for (size_t i = 0; i < ntimes; i++){//v.push_back(malloc(16));v.push_back(malloc((16 + i) % 8192 + 1));}size_t end1 = clock();size_t begin2 = clock();for (size_t i = 0; i < ntimes; i++){free(v[i]);}size_t end2 = clock();v.clear();malloc_costtime += (end1 - begin1);free_costtime += (end2 - begin2);}});}for (auto& t : vthread){t.join();}printf("%u个线程并发执行%u轮次,每轮次malloc %u次: 花费:%u ms\n",nworks, rounds, ntimes, (unsigned int)malloc_costtime);printf("%u个线程并发执行%u轮次,每轮次free %u次: 花费:%u ms\n",nworks, rounds, ntimes, (unsigned int)free_costtime);printf("%u个线程并发malloc&free %u次,总计花费:%u ms\n",nworks, nworks * rounds * ntimes, (unsigned int)malloc_costtime + free_costtime);
}// 单轮次申请释放次数 线程数 轮次
void BenchmarkConcurrentMalloc(size_t ntimes, size_t nworks, size_t rounds)
{std::vector<std::thread> vthread(nworks);std::atomic<size_t> malloc_costtime = 0;std::atomic<size_t> free_costtime = 0;for (size_t k = 0; k < nworks; ++k){vthread[k] = std::thread([&]() {std::vector<void*> v;v.reserve(ntimes);for (size_t j = 0; j < rounds; ++j){size_t begin1 = clock();for (size_t i = 0; i < ntimes; i++){//v.push_back(ConcurrentAlloc(16));v.push_back(ConcurrentAlloc((16 + i) % 8192 + 1));}size_t end1 = clock();size_t begin2 = clock();for (size_t i = 0; i < ntimes; i++){ConcurrentFree(v[i]);}size_t end2 = clock();v.clear();malloc_costtime += (end1 - begin1);free_costtime += (end2 - begin2);}});}for (auto& t : vthread){t.join();}printf("%u个线程并发执行%u轮次,每轮次concurrent alloc %u次: 花费:%u ms\n",nworks, rounds, ntimes, (unsigned int)malloc_costtime);printf("%u个线程并发执行%u轮次,每轮次concurrent dealloc %u次: 花费:%u ms\n",nworks, rounds, ntimes, (unsigned int)free_costtime);printf("%u个线程并发concurrent alloc&dealloc %u次,总计花费:%u ms\n",nworks, nworks * rounds * ntimes, malloc_costtime + free_costtime);
}int main()
{size_t n = 10000;cout << "==========================================================" << endl;BenchmarkConcurrentMalloc(n, 10, 10);cout << endl << endl;BenchmarkMalloc(n, 10, 10);cout << "==========================================================" << endl;return 0;
}

测试结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

性能测试

多线程环境下的内存分配/释放压力测试:
void MultiThreadAlloc1()
{std::vector<void*> v;for (size_t i = 0; i < 7; ++i){void* ptr = ConcurrentAlloc(6);v.push_back(ptr);}for (auto e : v){ConcurrentFree(e);}
}

测试结果:

  1. ThreadCache 的批量分配和释放机制
  2. 对象在ThreadCache和CentralCache间的流动
  3. 内存池的资源保留策略
  4. 整个生命周期没有内存泄漏
内存碎片化测试:
void TestFragmentation() {const int BLOCK_COUNT = 500;std::vector<void*> mediumBlocks;std::vector<void*> smallBlocks;// 分配中型内存块 (32KB)for (int i = 0; i < BLOCK_COUNT; ++i) {mediumBlocks.push_back(ConcurrentAlloc(32 * 1024));}// 释放75%的中型块(制造碎片)for (int i = 0; i < BLOCK_COUNT * 3/4; ++i) {ConcurrentFree(mediumBlocks[i]);}// 分配大量小内存块 (128B)for (int i = 0; i < BLOCK_COUNT * 10; ++i) {smallBlocks.push_back(ConcurrentAlloc(128));}// 尝试分配大内存块void* bigBlock = ConcurrentAlloc(128 * 1024);assert(bigBlock != nullptr && "Fragmentation may be too high!");// 清理ConcurrentFree(bigBlock);for (auto p : smallBlocks) ConcurrentFree(p);for (int i = BLOCK_COUNT * 3/4; i < BLOCK_COUNT; ++i) {ConcurrentFree(mediumBlocks[i]);}std::cout << "Fragmentation Test: Passed\n";
}

测试结果:

  1. 在高度碎片化的环境中仍能分配大内存块
  2. 自动合并相邻空闲Span的能力
  3. 正确处理不同大小内存块的混合分配
  4. 资源完全回收无泄漏
http://www.xdnf.cn/news/1439911.html

相关文章:

  • 根据fullcalendar实现企业微信的拖动式预约会议
  • Linux 用户的 Windows 改造之旅
  • Web端最强中继器表格元件库来了!55页高保真交互案例,Axure 9/10/11通用
  • 使用langgraph创建工作流系列3:增加记忆
  • 100种高级数据结构 (速查表)
  • 【NVIDIA B200】1.alltoall_perf 单机性能深度分析:基于 alltoall_perf 测试数据
  • 如何评价2025年数学建模国赛?
  • Debezium系列之:Flink SQL消费Debezium数据,只消费新增数据,过滤掉更新、删除数据
  • 计算机毕业设计选题推荐:基于Python+Django的新能源汽车数据分析系统
  • AI随笔番外 · 猫猫狐狐的尾巴式技术分享
  • Networking Concepts
  • 超越马力欧:如何为经典2D平台游戏注入全新灵魂
  • vue 手动书写步骤条
  • 用Blender制作Rat Rod风格汽车
  • MySQL 8.0.40 主从复制完整实验总结(基础搭建 + 进阶延时同步与误操作恢复)
  • 智能电视小米电视浏览器兼容性踩坑电视黑屏或者电视白屏,Vue项目从Axios到Fetch的避坑指南
  • GitHub每日最火火火项目(9.3)
  • 演员-评论员算法有何优点?
  • 《探索C++11:现代语法的性能优化策略(中篇)》
  • 从公共形象到专属定制,井云交互数字人满足金融/政务多元需求
  • etcd对比redis
  • MySQL--CRUD
  • Oracle 10g 安装教程(详解,从exe安装到数据库配置,附安装包)​
  • 食物分类案例优化改进 (数据增强,最优模型保存和使用)
  • oracle 从一张表更新到另外一张表的方法(MERGE)
  • IO进程线程;进程,发送信号;进程,消息队列通信;0903
  • 如何利用SMS、RDS把服务从阿里云迁移到华为云
  • FastGPT社区版大语言模型知识库、Agent开源项目推荐
  • 矿山 6KV 不接地系统中的绝缘监测解决方案
  • 简述 Java 的异常体系结构。Error 和 Exception 有什么区别?