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

《C++实战项目-高并发内存池》8. 最终性能优化与测试

Yupureki:个人主页✨个人专栏:《C》 《算法》《Linux系统编程》《高并发内存池》Yupureki的简介:目录1. 使用基数树进行优化2. 性能测试完整项目链接https://github.com/Yupureki-code/ConcurrentMemoryPool1. 使用基数树进行优化现内存池中存在一个比较严重的性能问题:PageCache需要加锁。特别是查找页ID到Span的映射时因为PageCache中不断存在修改的情况如果在一个线程查询的过程中另一个线程同时把这个Span给拿走了那就出大问题了。同时这把锁直接把整个PageCache给锁住了因此对锁的竞争会很严重同时没抢到锁的线程会一直在外面干瞪眼这造成了严重的性能浪费因此Google的大佬们使用了一个新的数据结构:基数树感兴趣的可以了解:Linux Kernel内核数据结构之基数树Radix Tree - 知乎基数树写之前会提前开好空间写数据过程中不会动结构。因为读写是分离的。线程1对一个位置读写的时候线程2不可能对这个位置读写。TCMalloc源码中有三个基数树的模板适用于不同的场景这里我们只使用前两个模板注意:该项目暂时只能在32位平台下使用基数树TCMalloc基数树(略微修改):#pragma once #include Common.h #include ObjectPool.h // Single-level array template int BITS class TCMalloc_PageMap1 { private: static const int LENGTH 1 BITS; void** array_; public: typedef uintptr_t Number; //explicit TCMalloc_PageMap1(void* (*allocator)(size_t)) { explicit TCMalloc_PageMap1() { //array_ reinterpret_castvoid**((*allocator)(sizeof(void*) BITS)); size_t size sizeof(void*) BITS; size_t alignSize SizeClass::_RoundUp(size, 1 PAGE_SHIFT); array_ (void**)SystemAlloc(alignSize PAGE_SHIFT); memset(array_, 0, sizeof(void*) BITS); } // Return the current value for KEY. Returns NULL if not yet set, // or if k is out of range. void* get(Number k) const { if ((k BITS) 0) { return NULL; } return array_[k]; } // REQUIRES k is in range [0,2^BITS-1]. // REQUIRES k has been ensured before. // // Sets the value v for key k. void set(Number k, void* v) { array_[k] v; } }; // Two-level radix tree template int BITS class TCMalloc_PageMap2 { private: // Put 32 entries in the root and (2^BITS)/32 entries in each leaf. static const PAGE_ID ROOT_BITS 5; static const PAGE_ID ROOT_LENGTH (PAGE_ID)1 ROOT_BITS; static const PAGE_ID LEAF_BITS BITS - ROOT_BITS; static const PAGE_ID LEAF_LENGTH (PAGE_ID)1 LEAF_BITS; // Leaf node struct Leaf { void* values[LEAF_LENGTH]; }; Leaf* root_[ROOT_LENGTH]; // Pointers to 32 child nodes void* (*allocator_)(size_t); // Memory allocator public: typedef uintptr_t Number; //explicit TCMalloc_PageMap2(void* (*allocator)(size_t)) { explicit TCMalloc_PageMap2() { //allocator_ allocator; memset(root_, 0, sizeof(root_)); PreallocateMoreMemory(); } void* get(Number k) const { const Number i1 k LEAF_BITS; const Number i2 k (LEAF_LENGTH - 1); if ((k BITS) 0 || root_[i1] NULL) { return NULL; } return root_[i1]-values[i2]; } void set(Number k, void* v) { const Number i1 k LEAF_BITS; const Number i2 k (LEAF_LENGTH - 1); // Defensive checks: k must fit in BITS and i1 must be within root range if ((k BITS) ! 0 || i1 ROOT_LENGTH) { // Out of range key: ignore or handle as appropriate return; } // Ensure leaf exists. Ensure() is responsible for allocating the leaf // and zero-initializing it. If Ensure fails, avoid writing. if (root_[i1] NULL) { if (!Ensure(k, 1)) { return; } } // Final bounds check for i2 to avoid corrupting memory if constants // are misconfigured or subject to UB elsewhere. if (i2 LEAF_LENGTH) { return; } root_[i1]-values[i2] v; } bool Ensure(Number start, size_t n) { for (Number key start; key start n - 1;) { const Number i1 key LEAF_BITS; // Check for overflow if (i1 ROOT_LENGTH) return false; // Make 2nd level node if necessary if (root_[i1] NULL) { //Leaf* leaf reinterpret_castLeaf*((*allocator_)(sizeof(Leaf))); //if (leaf NULL) return false; static ObjectPoolLeaf leafPool; Leaf* leaf (Leaf*)leafPool.New(); memset(leaf, 0, sizeof(*leaf)); root_[i1] leaf; } // Advance key past whatever is covered by this leaf node key ((key LEAF_BITS) 1) LEAF_BITS; } return true; } void PreallocateMoreMemory() { // Allocate enough to keep track of all possible pages Ensure(0, (PAGE_ID)1 BITS); } }; // Three-level radix tree template int BITS class TCMalloc_PageMap3 { private: // How many bits should we consume at each interior level static const int INTERIOR_BITS (BITS 2) / 3; // Round-up static const int INTERIOR_LENGTH 1 INTERIOR_BITS; // How many bits should we consume at leaf level static const int LEAF_BITS BITS - 2 * INTERIOR_BITS; static const int LEAF_LENGTH 1 LEAF_BITS; // Interior node struct Node { Node* ptrs[INTERIOR_LENGTH]; }; // Leaf node struct Leaf { void* values[LEAF_LENGTH]; }; Node* root_; // Root of radix tree void* (*allocator_)(size_t); // Memory allocator Node* NewNode() { Node* result reinterpret_castNode*((*allocator_)(sizeof(Node))); if (result ! NULL) { memset(result, 0, sizeof(*result)); } return result; } public: typedef uintptr_t Number; explicit TCMalloc_PageMap3(void* (*allocator)(size_t)) { allocator_ allocator; root_ NewNode(); } void* get(Number k) const { const Number i1 k (LEAF_BITS INTERIOR_BITS); const Number i2 (k LEAF_BITS) (INTERIOR_LENGTH - 1); const Number i3 k (LEAF_LENGTH - 1); if ((k BITS) 0 || root_-ptrs[i1] NULL || root_-ptrs[i1]-ptrs[i2] NULL) { return NULL; } return reinterpret_castLeaf*(root_-ptrs[i1]-ptrs[i2])-values[i3]; } void set(Number k, void* v) { ASSERT(k BITS 0); const Number i1 k (LEAF_BITS INTERIOR_BITS); const Number i2 (k LEAF_BITS) (INTERIOR_LENGTH - 1); const Number i3 k (LEAF_LENGTH - 1); reinterpret_castLeaf*(root_-ptrs[i1]-ptrs[i2])-values[i3] v; } bool Ensure(Number start, size_t n) { for (Number key start; key start n - 1;) { const Number i1 key (LEAF_BITS INTERIOR_BITS); const Number i2 (key LEAF_BITS) (INTERIOR_LENGTH - 1); // Check for overflow if (i1 INTERIOR_LENGTH || i2 INTERIOR_LENGTH) return false; // Make 2nd level node if necessary if (root_-ptrs[i1] NULL) { Node* n NewNode(); if (n NULL) return false; root_-ptrs[i1] n; } // Make leaf node if necessary if (root_-ptrs[i1]-ptrs[i2] NULL) { Leaf* leaf reinterpret_castLeaf*((*allocator_)(sizeof(Leaf))); if (leaf NULL) return false; memset(leaf, 0, sizeof(*leaf)); root_-ptrs[i1]-ptrs[i2] reinterpret_castNode*(leaf); } // Advance key past whatever is covered by this leaf node key ((key LEAF_BITS) 1) LEAF_BITS; } return true; } void PreallocateMoreMemory() { } };我们使用基数树替换SpanMap原本的哈希表结构TCMalloc_PageMap232 - PAGE_SHIFT _id_span_map;同时部分接口也需要替换:set(key,value)如:Span* PageCache::NewSpan(size_t k) { assert(k 0); if (k NPAGES - 1) { ...... _id_span_map.set(id, span); return span; } if (!_spanlists[k].Empty()) { Span* kspan _spanlists[k].PopFront(); for (size_t i 0; i kspan-_num; i) _id_span_map.set(kspan-_page_id i, kspan); return kspan; } for (size_t i k 1; i NPAGES; i) { if (!_spanlists[i].Empty()) { ...... _id_span_map.set(nspan-_page_id,nspan); _id_span_map.set(nspan-_page_id nspan-_num - 1,nspan); for (size_t i 0; i kspan-_num; i) _id_span_map.set(kspan-_page_id i,kspan); return kspan; } } ...... return NewSpan(k); }get(key)返回值:value如:Span* PageCache::SpanMapFindObject(void* ptr) { PAGE_ID id ((PAGE_ID)ptr PAGE_SHIFT); Span* span (Span*)_id_span_map.get(id); assert(span ! nullptr); return span; }2. 性能测试// ntimes 一轮申请和释放内存的次数 // rounds 轮次 void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds) { std::vectorstd::thread vthread(nworks); std::atomicsize_t malloc_costtime 0; std::atomicsize_t free_costtime 0; for (size_t k 0; k nworks; k) { vthread[k] std::thread([, k]() { std::vectorvoid* 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(%zu个线程并发执行%zu轮次每轮次malloc %zu次: 花费%zu ms\n, nworks, rounds, ntimes, malloc_costtime.load()); printf(%zu个线程并发执行%zu轮次每轮次free %zu次: 花费%zu ms\n, nworks, rounds, ntimes, free_costtime.load()); printf(%zu个线程并发mallocfree %zu次总计花费%zu ms\n, nworks, nworks * rounds * ntimes, malloc_costtime.load() free_costtime.load()); } // 单轮次申请释放次数 线程数 轮次 void BenchmarkConcurrentMalloc(size_t ntimes, size_t nworks, size_t rounds) { std::vectorstd::thread vthread(nworks); std::atomicsize_t malloc_costtime 0; std::atomicsize_t free_costtime 0; for (size_t k 0; k nworks; k) { vthread[k] std::thread([]() { std::vectorvoid* 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) { ConcurrentDealloc(v[i]); } size_t end2 clock(); v.clear(); malloc_costtime (end1 - begin1); free_costtime (end2 - begin2); } }); } for (auto t : vthread) { t.join(); } printf(%zu个线程并发执行%zu轮次每轮次concurrent alloc %zu次: 花费%zu ms\n, nworks, rounds, ntimes, malloc_costtime.load()); printf(%zu个线程并发执行%zu轮次每轮次concurrent dealloc %zu次: 花费%zu ms\n, nworks, rounds, ntimes, free_costtime.load()); printf(%zu个线程并发concurrent allocdealloc %zu次总计花费%zu ms\n, nworks, nworks * rounds * ntimes, malloc_costtime.load() free_costtime.load()); } int main() { size_t n 10000; std::cout std::endl; BenchmarkConcurrentMalloc(n, 4, 10); std::cout std::endl std::endl; BenchmarkMalloc(n, 4, 10); std::cout std::endl; return 0; }

相关文章:

《C++实战项目-高并发内存池》8. 最终性能优化与测试

💡Yupureki:个人主页 ✨个人专栏:《C》 《算法》《Linux系统编程》《高并发内存池》 🌸Yupureki🌸的简介: 目录 1. 使用基数树进行优化 2. 性能测试 完整项目链接https://github.com/Yupureki-code/ConcurrentMemoryPool 1. 使用基数树进行…...

网络安全--Windows操作系统

(新手小白入门网络安全,学习Windows操作系统基础知识,如有错误,欢迎批评指正!)一、初识操作系统操作系统(Operating System,简称OS)是管理和控制计算机硬件与软件资源的计…...

刷招聘软件时的迟疑?AI大模型才是程序员的新底气

刷着招聘APP的你,是否也曾突然陷入迟疑? 屏幕上密密麻麻的“大模型工程师”“AIGC应用开发工程师”岗位,技能要求写得愈发细致具体,从模型微调、Prompt工程到落地部署,条条直指AI领域。反观自己简历上引以为傲的“微服…...

2026 AI风口下,普通人(含程序员/小白)可落地的高薪岗位指南

国家统计局1月19日最新发布的数据,相信不少人都刷到了:2025年全国居民人均可支配收入达43377元,同比增长5.0%。这个数字看似稳健增长,但懂行的人都清楚,收入差距正被新一轮行业风口悄悄拉大,而2026年最具爆…...

从零开始构建Agentic RAG系统:LangGraph+Qwen打造智能自适应RAG

本文详细介绍Agentic RAG系统的构建方法,该系统融合动态查询分析和自我纠错机制,能够根据查询复杂度自适应选择检索与生成策略。文章基于LangGraph和Qwen模型,从状态管理、查询路由、文档检索、网络搜索到幻觉检测等11个步骤,完整…...

‌智慧校园系统价格解析:如何看懂报价背后的逻辑与选择适合自己的方案?

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…...

别再死磕 Python 了!这 4 款低代码工具也能做深度数据分析!

目录 一、FineBI 二、活字格 BI 插件 三、钉钉宜搭 QuickBI 四、Power BI 五、工具总结与对比 常见问答 想用数据驱动业务,却被代码给困住了? 业务那边急着要数据,你还在和Python库的版本兼容问题较劲……卡在脚本报错里寸步难行。 …...

计科-Linux4-中文件查看命令的详细介绍「整理」

...

妥妥的豪华局 —— 让 AI 来做照片分析

虽然 AI 无法给出所有的准确分析。 尝试使用 AI 分析一张照片,照片上的不少细节 AI 都注意到了,尤其是对中美使用餐具的情况做了对比。 同时,口味判断是准确的。 同时,给出的照片中,删除了所有的 EXIF 信息&#xff…...

静止同步调相机——01 无功补偿原理

无功补偿原理...

黄金悖论:无用的巅峰

“僭越者”的冠冕:黄金的终极悖论这一次,黄金的暴涨显得如此理所当然,甚至带着一丝命定的傲慢。然而,在其君临天下的价格曲线之下,涌动着一个深刻而古老的悖论:它正因其“无用”,而达至了“大用…...

仓库管理五大法:收、管、存、发、盘

目录 头条标题:仓库管理必看:收、管、存、发、盘5大方法 一、收:入库管理,把好物料入口关 1、单据到达 2、实物核对 3、办理入库 4、信息更新 二、管:在库管理,做好物料日常管控 1、分区分类 2、货…...

基于有源阻尼的PMSM高阻尼复矢量电流控制仿真、有参考文献

✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码及仿真咨询…...

【独家原创】基于(蜜獾算法)HBA-Transformer单变量时序预测(单输入单输出) Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室🍊个人信条:格物致知,完整Matlab代码及仿真咨询…...

【独家原创】基于(黏菌算法)SMA-Transformer多变量回归预测(多输入单输出) Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

基于DE-Transformer多变量时序预测 (多输入单输出)Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

【路径规划】基于Q-Learning实现的多机器人路径规划演示附matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

风电SCADA数据采集物联网解决方案

风电SCADA能够实时采集风电机组的运行数据,并对风力发电机组进行监视和控制,确保风电场安全高效地运行。现要求将SCADA数据采集到云服务器中,实现远程化的管理和应用。对此,物通博联(WideIOT)提供高效可靠的…...

并行算法在STL中的应用

1、非修改序列算法这些算法不会改变它们所操作的容器中的元素。1.1 find 和 find_iffind(begin, end, value):查找第一个等于 value 的元素,返回迭代器(未找到返回 end)。find_if(begin, end, predicate):查找第一个满…...

基于DE-Transformer单变量时序预测 (单输入单输出)Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

【数据分析】数据驱动预测控制策略的比较分析附matlab代码复现

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

P8638 [蓝桥杯 2016 省 A] 密码脱落【LCS】

P8638 [蓝桥杯 2016 省 A] 密码脱落 题目描述 X 星球的考古学家发现了一批古代留下来的密码。 这些密码是由 A、B、C、D 四种植物的种子串成的序列。 仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的回文串)。 由于年代久远…...

Spring Cloud Circuit Breaker 2.0.0 M1(Milestone 1)是 Spring Cloud 官方在 2022 年初发布的

Spring Cloud Circuit Breaker 2.0.0 M1(Milestone 1)是 Spring Cloud 官方在 2022 年初发布的 Spring Cloud Circuit Breaker 2.x 系列的首个里程碑版本,标志着该项目从旧版 spring-cloud-netflix-hystrix(已停更)和早期 spring-cloud-circuitbreaker(1.x)向统一、轻量…...

PCL: CorrespondenceEstimationNormalShooting的使用【2026最新版】

目录 一、 算法简介 二、 代码实现 1、原始版本 2、2026新版 三、结果展示 本文由CSDN点云侠原创,原文链接,首发于:2020年5月11日。博客长期更新,本文最近一次更新时间为:2026年3月15日。 一、 算法简介 pcl::registration::CorrespondenceEstimationNormalShooting< …...

Elasticsearch相关技术点

目录 ES数据结构、倒排索引、写入流程、读取流程 ES检索快的核心原因 Elasticsearch 性能优化 Elasticsearch 和 Kafka 数据结构对比 什么场景下使用了ES?//todo 项目中什么场景用了ES ES 怎么用的?数据量级多少?为什么用ES 不用Hbase? 倒排索引 是什么讲一下? 为…...

Spring Cloud Config 2.2.2 是 Spring Cloud 的一个**配置中心组件版本**

Spring Cloud Config 2.2.2 是 Spring Cloud 的一个配置中心组件版本&#xff0c;发布于 2020 年 3 月&#xff08;属于 Spring Cloud Hoxton.SR3 版本栈&#xff09;&#xff0c;基于 Spring Boot 2.2.x 构建。该版本已停止官方维护&#xff08;EOL&#xff09;&#xff0c;Sp…...

Spring Cloud App Broker 1.0.5 是 Spring Cloud 团队发布的用于构建云原生服务代理(Service Broker)的开源框架的一个维护版本

Spring Cloud App Broker 1.0.5 是 Spring Cloud 团队发布的用于构建云原生服务代理&#xff08;Service Broker&#xff09;的开源框架的一个维护版本。该版本主要包含错误修复、安全补丁、依赖升级&#xff08;如 Spring Boot、Spring Cloud 及相关组件的兼容性更新&#xff…...

java毕业设计——基于JSP+sqlserver的网上书店系统设计与实现(毕业论文+程序源码)——网上书店

基于JSPsqlserver的网上书店系统设计与实现&#xff08;毕业论文程序源码&#xff09; 大家好&#xff0c;今天给大家介绍基于JSPsqlserver的网上书店系统设计与实现&#xff0c;文章末尾附有本毕业设计的论文和源码下载地址哦。需要下载开题报告PPT模板及论文答辩PPT模板等的…...

java毕业设计——基于JSP+sqlserver的网上购物系统设计与实现(毕业论文+程序源码)——网上购物系统

基于JSPsqlserver的网上购物系统设计与实现&#xff08;毕业论文程序源码&#xff09; 大家好&#xff0c;今天给大家介绍基于JSPsqlserver的网上购物系统设计与实现&#xff0c;文章末尾附有本毕业设计的论文和源码下载地址哦。需要下载开题报告PPT模板及论文答辩PPT模板等的…...

java毕业设计——基于JSP+sqlserver的网络远程作业处理系统设计与实现(毕业论文+程序源码)——网络远程作业处理系统

基于JSPsqlserver的网络远程作业处理系统设计与实现&#xff08;毕业论文程序源码&#xff09; 大家好&#xff0c;今天给大家介绍基于JSPsqlserver的网络远程作业处理系统设计与实现&#xff0c;文章末尾附有本毕业设计的论文和源码下载地址哦。需要下载开题报告PPT模板及论文…...