一、项目背景

  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.pswp.cn/bicheng/95570.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/95570.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/95570.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

吱吱企业通讯软件以安全为核心,构建高效沟通与协作一体化平台

随着即时通讯工具日益普及&#xff0c;企业面临一个严峻的挑战&#xff1a;如何在保障通讯数据安全的前提下&#xff0c;提升办公效率&#xff1f;为解决此问题&#xff0c;吱吱企业通讯软件诞生&#xff0c;通过私有化部署和深度集成的办公系统&#xff0c;为企业打造一个既可…

校企合作| 长春大学旅游学院副董事长张海涛率队到访卓翼智能,共绘无人机技术赋能“AI+文旅”发展新蓝图

为积极响应国务院《关于深入实施“人工智能”行动的意见》&#xff08;国发〔2025〕11号&#xff09;号召&#xff0c;扎实推进学校“旅游”与“人工智能”双轮驱动的学科发展战略&#xff0c;加快无人机技术在文旅领域的创新应用&#xff0c;近日长春大学旅游学院副董事长张海…

为什么要用 MarkItDown?以及如何使用它

在处理大量文档时&#xff0c;尤其是在构建知识库、进行文档分析或训练大语言模型&#xff08;LLM&#xff09;时&#xff0c;将各种格式的文件&#xff08;如 PDF、Word、Excel、PPT、HTML 等&#xff09;转换为统一的 Markdown 格式&#xff0c;能够显著提高处理效率和兼容性…

LVGL9.3 vscode 模拟环境搭建

1、git 克隆&#xff1a; git clone -b release/v9.3 https://github.com/lvgl/lv_port_pc_vscode.git 2、cmake 和 mingw 环境搭建 cmake&#xff1a; https://blog.csdn.net/qq_51355375/article/details/139186681?spm1011.2415.3001.5331 mingw&#xff1a; https://bl…

投影矩阵:计算机图形学中的三维到二维转换

投影矩阵是计算机图形学中的核心概念之一&#xff0c;它负责将三维场景中的几何数据投影到二维屏幕上&#xff0c;从而实现三维到二维的转换。无论是游戏开发、虚拟现实&#xff0c;还是3D建模&#xff0c;投影矩阵都扮演着不可或缺的角色。本文将深入探讨投影矩阵的基本原理、…

10.2 工程学中的矩阵(2)

十、例题 【例3】求由弹簧连接的 100100100 个质点的位移 u(1),u(2),...,u(100)u(1),u(2),...,u(100)u(1),u(2),...,u(100), 弹性系数均为 c1c 1c1, 每个质点受到的外力均为 f(i)0.01f(i)0.01f(i)0.01. 画出两端固定和固定-自由这两种情形 u 的图形。 解&#xff1a; % 参数设…

Mysql主从复制之延时同步

1.延时同步概念通过人为配置从库和主库延时N小时可以实现延时同步&#xff0c;延时同步可以解决数据库故障出现的数据丢失问题(物理损坏如直接使用rm删除数据库数据和逻辑损坏如使用drop命令删除数据库)2.延时同步实操2.1先配置从库延时同步&#xff0c;并且设置sql线程300秒后…

【QT特性技术讲解】QPrinter、QPdf

前言 QT对打印和PDF应用场景&#xff0c;做了简单的封装&#xff0c;复杂的功能还是得用第三方库&#xff0c;打印功能简单的文本可以不用PDF&#xff0c;涉及图形的基本都要用到PDF。 Linux打印 随着国产信创项目替换基于Linux的桌面系统国产信创系统&#xff0c;Linux桌面系…

【大数据技术实战】Flink+DS+Dinky 自动化构建数仓平台

一、背景&#xff1a;企业数仓建设的现状与挑战在数字化转型进入深水区的今天&#xff0c;数据已成为企业核心生产要素&#xff0c;而实时数仓作为 “数据驱动决策” 的关键载体&#xff0c;其建设水平直接决定企业在市场竞争中的响应速度与决策精度。根据 IDC《2024 年全球大数…

Python开篇:撬动未来的万能钥匙 —— 从入门到架构的全链路指南

Python&#xff1a;撬动未来的万能钥匙——从入门到架构的全链路指南 在技术的星空中&#xff0c;Python 是那颗永不陨落的超新星——它用简洁的语法点燃创造之火&#xff0c;以庞大的生态铺就革新之路。无论你身处哪个领域&#xff0c;这把钥匙正在打开下一个时代的大门。2024…

【QT随笔】事件过滤器(installEventFilter 和 eventFilter 的组合)之生命周期管理详解

【QT随笔】事件过滤器(installEventFilter 和 eventFilter 的组合)之生命周期管理详解 上一章节中提到事件过滤器(Event Filter),用于处理特定事件。其中第二小节中提到了事件过滤器生命周期管理。本文将详细解析事件过滤器生命周期管理这一部分的内容。 (关注不迷路哈!…

关于linux软件编程12——网络编程3

一、单循环服务器 特点:1.可以处理多个客户端 (不能同时)2.效率不高//单循环服务器: socket bind listen while (1) {connfd accept();//通信 }特点:简单 可以处理多客户端 不能同时 二、并发服务器 --- 同时可以处理多个客户端1、设置一个选项(开启一个功能) ---让地址重…

thinkphp6通过workerman使用websocket

安装workerman依赖 composer require topthink/think-worker composer require topthink/think-worker1.0.* # 指定兼容版本‌:ml-citation{ref"1,7" data"citationList"}config配置 config/worker.php <?php return [// 扩展自身需要的配置host …

Rust SQLx 开发指南:利用 Tokio 进行性能优化

在当今高并发的应用开发环境中&#xff0c;数据库操作往往是性能瓶颈的主要来源之一。SQLx 作为一个纯 Rust 编写的异步 SQL 客户端库&#xff0c;通过与 Tokio 运行时深度集成&#xff0c;为开发者提供了处理数据库 I/O 密集型操作的强大工具。本文将带您深入了解如何利用这两…

嵌入式硬件电路分析---AD采集电路

文章目录摘要AD采集电路1AD采集电路2R77的真正作用是什么&#xff1f;理想与现实&#xff1a;为什么通常可以忽略R77的影响&#xff1f;摘要 AD采集 AD采集电路1 这是个人画的简化后的AD采集电路 这是一个AD检测电路&#xff0c;R1是一个可变电阻&#xff0c;R2是根据R1的常用…

Python爬取nc数据

1、单文件爬取爬取该网站下的crupre.nc数据&#xff0c;如下使用requests库&#xff0c;然后填写网站的url&#xff1a;"http://clima-dods.ictp.it/regcm4/CLM45/crudata/"和需要下载的文件名&#xff1a;"crupre.nc"import requests import osdef downlo…

策略模式 + 工厂模式

策略模式&#xff1a;简单来说解决的行为的封装与选择。如HandlerMapping&#xff0c;将 HTTP 请求映射到对应的处理器&#xff08;Controller 或方法&#xff09;。工厂模式&#xff1a;解决的是具有相同属性的对象创建问题&#xff0c;如BeanFactory创建bean对象。解决的代码…

Diamond基础3:在线逻辑分析仪Reveal的使用

文章目录1. 与ILA的区别2. 使用Reveal步骤3.Reveal注意事项4.传送门1. 与ILA的区别 Reveal是Lattice Diamond集成开发环境用于在线监测信号的工具&#xff0c;ILA是xilinx的Vivado集成开发工具的在线逻辑分析仪&#xff0c;同Reveal一样&#xff0c;均可以在项目运行过程中&am…

超适合程序员做知识整理的 AI 网站

这次要给大家分享一个超适合程序员做知识整理的 AI 网站 ——Notion AI&#xff0c;网址是Notion&#xff0c;它能把你随手记的杂乱笔记、代码片段、技术文档&#xff0c;一键梳理成逻辑清晰的结构化内容&#xff0c;小索奇我用它整理 “Python 爬虫知识点” 时&#xff0c;原本…

【 Selenium 爬虫】2025年8月25日-pixabay 图片采集

无恶意采集&#xff0c;取部分图片用来做相册测试的&#x1f604; 效果图import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.la.selenium.utils.SeleniumUtil; import lombok.extern.slf4j.Slf4j; import o…