【项目日记(九)】项目整体测试,优化以及缺陷分析
💓博主CSDN主页:杭电码农-NEO💓
⏩专栏分类:项目日记-高并发内存池⏪
🚚代码仓库:NEO的学习日记🚚
🌹关注我🫵带你做项目
🔝🔝
开发环境:Visual Studio 2022
项目日记
- 1. 前言
- 2. 整体项目测试
- 3. 项目的效率上限分析
- 4. 效率上限问题的解决方法
- 5. 项目的缺陷分析
- 6. 项目总结
1. 前言
整个项目的代码和框架就已经介绍
完毕了,项目的所有代码在下面的链接:
gitee代码仓库项目源代码
本章重点:
本篇文章着重讲解本项目是如何测试的,
以及本代码的一些效率上限问题,最后会
引入基数树来对项目整体做优化
2. 整体项目测试
对本项目的测试无非就是将自己写的
内存池与C语言的malloc做对比,代码如下:
#include<cstdio>
#include<iostream>
#include<vector>
#include<thread>
#include<mutex>
#include"ConcurrentAlloc.h"
using namespace std;
void BenchmarkMalloc(size_t ntimes, size_t nworks, size_t rounds)//ntime一轮申请和释放内存的次数,round是跑多少轮,nworks是线程数
{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, malloc_costtime.load());printf("%u个线程并发执行%u轮次,每轮次free %u次: 花费:%u ms\n",nworks, rounds, ntimes, free_costtime.load());printf("%u个线程并发malloc&free %u次,总计花费:%u ms\n",nworks, nworks * rounds * ntimes, malloc_costtime.load() + free_costtime.load());
}// 单轮次申请释放次数 线程数 轮次
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, malloc_costtime.load());printf("%u个线程并发执行%u轮次,每轮次concurrent dealloc %u次: 花费:%u ms\n",nworks, rounds, ntimes, free_costtime.load());printf("%u个线程并发concurrent alloc&dealloc %u次,总计花费:%u ms\n",nworks, nworks * rounds * ntimes, malloc_costtime.load() + free_costtime.load());
}
int main()
{size_t n = 10000;cout << "==========================================================" << endl;BenchmarkConcurrentMalloc(n, 10, 10);cout << endl << endl;BenchmarkMalloc(n, 10, 10);cout << "==========================================================" <<endl;return 0;
}
本代码是现成的,不用在意细节
当我们运行代码后会发现,为什么我们自己写的内存池的效率比不上C语言中的malloc函数,这一点显然超出了我们的预期,下面就来分析一下项目的效率上限问题
3. 项目的效率上限分析
在vs的调试中有一个性能探测器
我们可以使用这个功能来分析哪个步骤比较用时,当我们完成检测后会发现,在pagecache文件中的函数耗时都比较久,其实我们隐约已经知道问题出现在哪里了,我们知道unordered_map的底层是哈希桶结构,然而find函数会将每一个桶中的链表都遍历一遍,直到找到了对应的key值,很明显这个查找的过程是比较费时的,并且如果不切换一个容器来代替unordered_map的话,在这个基础上不管怎样去优化都不会有质的提升!!!
4. 效率上限问题的解决方法
对于上面的问题显然超出了我们的能力范围,对于一个C++的初学者来说,标准库中的容器已经是很优秀的了,如果要抛弃标准库,我们也不能写出更好的,所以这里直接将TCmalloc开源项目中的解决方法给搬过来,谷歌的团队使用了一个叫基数树的结构来完美的解决此问题
基数树的文档说明:
基数树百度百科
由于基数树属于此项目的拓展内容,所以这里就不详细介绍了,完美直接把代码搬出来用就可以了!
#pragma once
#include"shared.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_cast<void**>((*allocator)(sizeof(void*) << BITS));size_t size = sizeof(void*) << BITS;size_t alignSize = AlignmentRule::_AlignUp(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;}
};
之后将所有使用unordered_map的地方都替换成基数树的get和set函数即可!现在我们再来测试一下整个项目的性能如何:
使用基数树后,整个效率就比malloc快了!
5. 项目的缺陷分析
本项目看似每一步都做的天衣无缝,申请
和释放内存一层一层不断递进,但是它有
一个致命的缺陷,那就是内存泄漏问题:
bug出现的情景:
假设线程缓存的K号桶中有10个小块儿内存挂在桶上,此时K号桶向中心缓存申请的小块儿内存个数是7个,小于了桶中小块儿内存的个数,此时会将线程缓存中的7个小块儿内存还给中心缓存,那么也就还剩下三个小块儿内存在桶中没有被还回去,此时如果没有线程来这个桶中申请或释放内存,那么这三块儿内存就会一直挂在桶上,既无法释放它,又失去了对它的控制从而造成内存泄漏!
解决bug的方式:
博主本人比较推荐的方式就是在每次使用完内存池后,手动调用一个释放内存的函数对每一个桶进行遍历,来释放还没有被使用的小块儿内存
6. 项目总结
高并发内存池项目到这里就结项了,
三层缓存结构设计的非常之巧妙,做
这个项目为了去解决某个问题,而是
去学习别人的优秀的,先进的思想
相关文章:

【项目日记(九)】项目整体测试,优化以及缺陷分析
💓博主CSDN主页:杭电码农-NEO💓 ⏩专栏分类:项目日记-高并发内存池⏪ 🚚代码仓库:NEO的学习日记🚚 🌹关注我🫵带你做项目 🔝🔝 开发环境: Visual Studio 2022 项目日…...
JavaScript 设计模式之外观模式
外观模式 我们为啥要使用外观模式呢,其实我们在使用各种 js 库的时候常常会看到很多的外观者模式,也正是这些库的大量使用,所以使得兼容性更广泛,通过外观者模式来封装多个功能,简化底层操作方法 const A {g: functi…...
一、基础数据结构——2.队列——3.双端队列和单调队列2
参考资料:《算法竞赛》,罗勇军 郭卫斌 著 本博客作为阅读本书的学习笔记,仅供交流学习。 建议关注 罗勇军老师博客 3. 单调队列与最大子序和问题 不限制子序列长度问题——贪心法或动态规划 HDOJ 1003 MAX SUM Max Sum Time Limit: 2000/10…...

Stable Diffusion 模型下载:Samaritan 3d Cartoon(撒玛利亚人 3d 卡通)
本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十...
【软件工程导论】实验二——编制数据字典(数字化校园系统案例分析)
数字化校园系统案例分析 问题定义实验内容编制内容1数据项数据流处理逻辑数据存储 2外部实体 问题定义 数字化校园系统期望以数字化信息和网络为基础,在计算机和网络技术上建立起对教学、科研、管理、技术服务、生活服务等校园信息的收集、处理、整合、存储、传输和…...

耳机壳UV树脂制作私模定制耳塞适合什么样的人使用呢?
耳机壳UV树脂制作私模定制耳塞适合以下人群使用: 对音质要求高的人:私模定制耳塞能够完美契合用户的耳朵形状,减少漏音和外部噪音的干扰,提供更好的音质体验。需要长时间佩戴耳机的人:私模定制耳塞能够提高佩戴舒适度…...

第三百一十回
我们在上一章回中介绍了"再谈ListView中的分隔线",本章回中将介绍showMenu的用法.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在第一百六十三回中介绍了showMenu相关的内容,它主要用来显示移动PopupMenu在页面中的位置…...

海量数据处理商用短链接生成器平台 - 4
第六章 架构核心技术-池化思想-异步结合 性能优化最佳实践 第1集 RestTemplate里面的存在的问题你知道多少- Broken pipe错误 项目就更新到第六章了,剩下的内容 放百度网盘里面了,需要的来取。 链接:https://pan.baidu.com/s/19LHPw36dsxPB7…...

基于CNN+LSTM深度学习网络的时间序列预测matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 卷积神经网络(CNN) 4.2 长短时记忆网络(LSTM) 4.3 CNNLSTM网络结构 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MA…...
如何控制系统安全 或 控制流氓软件
电脑 出入数据的地方是安全保障的最后一关 比如 网络 , usb 等等 控制联网流氓软件 1 在虚拟机里测试软件是否有恶意行为 恶意行为非常容易发现 比如 破坏文件 修改文件 系统不正常 像蓝屏 等等 2 网络防火墙 这是系统最关键的部分之一 像 windows 一定使用他…...

【Docker】Docker Container(容器)
文章目录 一、什么是容器?二、为什么需要容器?三、容器的生命周期容器OOM容器异常退出容器暂停 四、容器命令详解docker createdocker logsdocker attachdocker execdocker startdocker stopdocker restartdocker killdocker topdocker statsdocker cont…...

Amazon CodeWhisperer 免费 AI 代码生成助手体验分享
今年上半年,亚马逊云科技正式推出了实时AI编程助手 Amazon CodeWhisperer,还提供了供所有开发人员免费使用的个人版版本。经过一段时间的体验,我觉得 CodeWhisperer 可以处理编程工作中遇到的很多问题,并且帮助开发人员提高编程效…...

Spring Cloud Gateway 网关路由
一、路由断言 路由断言就是判断路由转发的规则 二、路由过滤器 1. 路由过滤器可以实现对网关请求的处理,可以使用 Gateway 提供的,也可以自定义过滤器 2. 路由过滤器 GatewayFilter(默认不生效,只有配置到路由后才会生效&#x…...

【Spring学习】Spring Data Redis:RedisTemplate、Repository、Cache注解
1,spring-data-redis官网 1)特点 提供了对不同Redis客户端的整合(Lettuce和Jedis)提供了RedisTemplate统一API来操作Redis支持Redis的发布订阅模型支持Redis哨兵和Redis集群支持基于Lettuce的响应式编程支持基于JDK、JSON、字符…...

C语言:内存函数
创作不易,友友们给个三连吧!! C语言标准库中有这样一些内存函数,让我们一起学习吧!! 一、memcpy函数的使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); 1.1 使…...

Go+:一种简单而强大的编程语言
Go是一种简单而强大的编程语言,它是在Go语言之上构建的,旨在提供更加强大、灵活和易于使用的编程体验。Go与Go语言共享大部分语法和语义,因此Go开发人员可以很快上手Go,同时也可以使用Go来编写更加简洁和高效的代码。在本文中&…...

【开源】SpringBoot框架开发数字化社区网格管理系统
目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、开发背景四、系统展示五、核心源码5.1 查询企事业单位5.2 查询流动人口5.3 查询精准扶贫5.4 查询案件5.5 查询人口 六、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数字化社区网格管理系统…...
Lua可变参数函数
基础规则 lua传入参数给一个function时采用的是“多余部分被忽略,缺少部分有nil补足”的形式: function f(a, b)return a or b endCALL PARAMETERS f(3) a3, bnil f(3, 4) a3, b4 f(3, 4, 5) a3, b4 (5 is discarded) unpack/pack…...

Nginx实战:3-日志按天分割
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、方式1:定时任务执行分割脚本 1.分割日志脚本 2.添加定时任务 二、方式2:logrotate配置分割 1.logrotate简单介绍 2.新增切割ngi…...
springmvc中的数据提交方式
一、单个数据提交数据 jsp代码: <h2>1单个数据提交</h2> <form action"${pageContext.request.contextPath}/one.action">name<input name"myname"/><br>age<input name"age"><input type&…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...

宇树科技,改名了!
提到国内具身智能和机器人领域的代表企业,那宇树科技(Unitree)必须名列其榜。 最近,宇树科技的一项新变动消息在业界引发了不少关注和讨论,即: 宇树向其合作伙伴发布了一封公司名称变更函称,因…...

嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...