高并发内存池(定长内存池基础)

定长内存池的设计

      • 定长内存池
      • 定长内存池的原理讲解
      • 代码实现
            • 定义对象
            • New对象的主要逻辑
            • delete对象的主要逻辑
            • 完整代码

定长内存池

为什么我们要设计这个定长内存池呢?首先malloc是c标准库中向堆申请空间的接口,变相的说malloc是普遍性,而我们要实现的高并发内存池是特殊性,是针对某种情况下把效率提高到极致的一种申请空间的方法。在后续我们的项目中也会用到定长内存池,所以定长内存池的设计有两方面,一是让我们熟悉一下内存的分配问题,二是他会作为我们的高并发内存池的一个基础组件。

定长内存池的原理讲解

首先我们需要在内存中申请一块固定大小的空间,如下图:
在这里插入图片描述

后面我们考虑如何分配空间以及管理后续的空间。这里我们像系统申请了一大块空间,如果再有用户需要申请空间这个时候我们就可以直接从我们管理的那一大块空间中取出空间,从而避免了重复申请和释放空间的效率问题。但是这里用户归还的空间我们也不能直接还给操作系统,所以我们需要使用一个freelist(自由链表)将归还的空间管理起来

在这里插入图片描述
在这里插入图片描述
每次从上面取完空间后,归还空间我们就直接头插到链表中。下次如果在需要申请,我们就可以直接使用_freelist中的空间直接给到用户使用。

代码实现

定义对象

我们先定义一个class ObjectPool类对象

#pragma once
#include<iostream>
using std::endl;
using std::cout;template<class T>
class Object {
public:
private:char* _memory = nullptr; //指向内存池的起始位置size_t _remain = 0;      //内存剩余空间大小void* _freelist = nullptr; //指向自由链表的第一个节点的指针
};

这里定义三个私有成员变量,具体用处见上述代码注释。

New对象的主要逻辑

首先我们对于空间申请的类,肯定就是new 和 delete两个重要的接口。我们先来写new:

T* New()
{T* obj = nullptr; //先顶一个返回的objif (_freelist)    //如果自由链表不为空,此时我们直接使用自由链表的空间{//这里就相当于链表的头删void* next = *(void**)_freelist; //定义一个next存储链表下一个节点的地址 obj = (T*)_freelist; //再让obj指向分配内存的首地址_freelist = next;    //再将自由链表连接到下一个节点处}else{if (_remain<sizeof(T))  //如果内存空间剩余大小小于当前类型的大小{//重新像系统申请一块大空间_remain = 128 * 1024; //更新内存剩余空间大小_memory = (char*)malloc(_remain); //开辟空间if (_memory == nullptr)  //如果_memory为空则报错{throw std::bad_alloc();}}obj = (T*)_memory;  //obj接收被切割的首地址size_t objsize = sizeof(T) < sizeof(void*) ?  sizeof(void*) : sizeof(T);  //这里为了防止开辟的空间没有办法储存地址,所以如果类型大小小于地址的大小,则开辟地址大小字节的空间,否则开辟类型大小的空间。_memory += objsize; //随后_memory指向后面的空间_remain -= objsize; //_remain减少//显示调用一下构造,应对string等这些类型的构造new(obj)T;return obj;}
}
delete对象的主要逻辑

delete就相当于是链表的头插

void Delete(T* obj)
{obj->~T();*(void**)obj = _freelist;_freelist = obj;
}

这里的主要逻辑就结束了,接下来对代码进行优化一下。
我们这里使用的还是malloc,所以我们还可以完全脱离malloc使用系统调用接口virtualalloc这个接口直接在堆上申请空间,接下来就是完整代码,还有一段测试的例子我们可以清楚的看到我们的定长内存池在申请同一类型的空间时效率的提升有多夸张。

完整代码

这里我们使用了条件编译用来区分windows和Linux中不同的系统调用接口。

#pragma once
#include<iostream>
#include<vector>using std::cout;
using std::endl;#ifdef _WIN32
#include<windows.h>
#else
// 
#endif
// 直接去堆上按页申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else// linux下brk mmap等
#endifif (ptr == nullptr)throw std::bad_alloc();return ptr;
}template<class T>
class ObjectPool{
public:T* New(){T* obj = nullptr;if (_freelist)//如果自由链表不为空则使用自由链表中的空间{void* next = *(void**)_freelist;obj = (T*)_freelist;_freelist = next;}else {if (_remain < sizeof(T)){_remain = 128 * 1024;//_memery = (char*)malloc(_remain);_memery = (char*)SystemAlloc(_remain>>13);if (_memery == nullptr){throw std::bad_alloc();}}obj = (T*)_memery;size_t objsize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);_memery += objsize;_remain -= objsize;}new(obj)T;return obj;}void Delete(T* obj){obj->~T();*(void**)obj = _freelist;_freelist = obj;}private:char* _memery = nullptr;//内存池起始地址size_t _remain = 0; //内存池剩余字节数void* _freelist = nullptr; //自由链表起始地址
};struct TreeNode
{int _val;TreeNode* _left;TreeNode* _right;TreeNode():_val(0), _left(nullptr), _right(nullptr){}
};void TestObjectPool()
{// 申请释放的轮次const size_t Rounds = 5;// 每轮申请释放多少次const size_t N = 100000;std::vector<TreeNode*> v1;v1.reserve(N);size_t begin1 = clock();for (size_t j = 0; j < Rounds; ++j){for (int i = 0; i < N; ++i){v1.push_back(new TreeNode);}for (int i = 0; i < N; ++i){delete v1[i];}v1.clear();}size_t end1 = clock();std::vector<TreeNode*> v2;v2.reserve(N);ObjectPool<TreeNode> TNPool;size_t begin2 = clock();for (size_t j = 0; j < Rounds; ++j){for (int i = 0; i < N; ++i){v2.push_back(TNPool.New());}for (int i = 0; i < N; ++i){TNPool.Delete(v2[i]);}v2.clear();}size_t end2 = clock();cout << "new cost time:" << end1 - begin1 << endl;cout << "object pool cost time:" << end2 - begin2 << endl;
}

Debug:在这里插入图片描述
Release:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/76843.shtml

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

相关文章

【VUE3】练习项目——大事件后台管理

目录 0 前言 1 准备工作 1.1 安装pnpm 1.2 创建vue项目 1.3 Eslint & Prettier的配置 1.4 husky 提交代码检查 1.5 目录调整 1.6 VueRouter4 1.6.1 基础配置 1.6.2 路由跳转 1.7 引入 Element Plus 组件库 1.8 Pinia 1.8.1 优化 1.9 封装请求工具 1.9.1 安…

WebSocket与MQTT

在物联网&#xff08;IoT&#xff09;领域&#xff0c;​WebSocket和MQTT确实都可以实现实时通信&#xff0c;但它们的核心设计目标、适用场景和角色存在显著差异。以下是两者的对比分析&#xff1a; ​1. 协议设计初衷​ ​WebSocket​ ​目标​&#xff1a;提供浏览器与服务器…

Mysql为什么有时候会选错索引

案例 正常情况 有一个表t ( id, a , b )&#xff0c;id是主键索引&#xff0c;a是Normal索引。 正常情况下&#xff0c;针对a进行查询&#xff0c;可以走索引a 并且查询的数量和预估扫描行数是差不多的&#xff0c;都是10001行 奇怪的现象 随着时间的变化&#xff0c;后…

[250414] ArcoLinux 项目宣布逐步结束

目录 ArcoLinux 项目宣布逐步结束 ArcoLinux 项目宣布逐步结束 备受欢迎的 Arch Linux 发行版 ArcoLinux 近日宣布&#xff0c;其项目将逐步结束。ArcoLinux 以其作为 Linux 教育平台和提供多种安装选项&#xff08;从完整桌面环境到最小化基础安装&#xff09;而闻名。 核心…

opencv人脸性别年龄检测

一、引言 在计算机视觉领域&#xff0c;人脸分析是一个热门且应用广泛的研究方向。其中&#xff0c;人脸性别年龄检测能够自动识别图像或视频流中人脸的性别和年龄信息&#xff0c;具有诸多实际应用场景&#xff0c;如市场调研、安防监控、用户个性化体验等。OpenCV 作为一个强…

【NLP】 22. NLP 现代教程:Transformer的训练与应用全景解读

&#x1f9e0; NLP 现代教程&#xff1a;Transformer的训练与应用全景解读 一、Transformer的使用方式&#xff08;Training and Use&#xff09; 如何使用Transformer模型&#xff1f; Transformer 模型最初的使用方式有两种主要方向&#xff1a; 类似 RNN 编码-解码器的架…

Spring Boot 集成 RocketMQ 全流程指南:从依赖引入到消息收发

前言 在分布式系统中&#xff0c;消息中间件是解耦服务、实现异步通信的核心组件。RocketMQ 作为阿里巴巴开源的高性能分布式消息中间件&#xff0c;凭借其高吞吐、低延迟、高可靠等特性&#xff0c;成为企业级应用的首选。而 Spring Boot 通过其“约定优于配置”的设计理念&a…

HTTPS实现安全的关键方法及技术细节

HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;通过多种技术手段实现数据传输的安全性&#xff0c;其核心机制基于SSL/TLS协议&#xff0c;并结合数字证书、加密算法等技术。 SSL&#xff1a;Secure Sockets Layer&#xff0c;安全套接字层 TLS&#xff1a;…

Java【多线程】(8)CAS与JUC组件

目录 1.前言 2.正文 2.1CAS概念 2.2CAS两种用途 2.2.1实现原子类 2.2.2实现自旋锁 2.3缺陷&#xff1a;ABA问题 2.4JUC组件 2.4.1Callable接口 2.4.2ReentrantLock&#xff08;与synchronized对比&#xff09; 2.4.3Semaphore信号量 2.4.4CountDownLatch 3.小结 1…

【Docker】离线安装Docker

背景 离线安装Docker的必要性&#xff0c;第一&#xff0c;在目前数据安全升级的情况下&#xff0c;很多外网已经基本不好访问了。第二&#xff0c;如果公司有对外部署的需求&#xff0c;那么难免会存在对方只有内网的情况&#xff0c;那么我们就要做到学会离线安装。 下载安…

MecAgent Copilot:机械设计师的AI助手,开启“氛围建模”新时代

MecAgent Copilot作为机械设计师的AI助手,正通过多项核心技术推动机械设计进入“氛围建模”新时代。以下从功能特性、技术支撑和应用场景三方面解析其创新价值: 一、核心功能特性 ​​智能草图生成与参数化建模​​ 支持自然语言输入生成设计草图和3D模型,如输入“剖面透视…

MCU屏和RGB屏

一、MCU屏 MCU屏‌&#xff1a;全称为单片机控制屏&#xff08;Microcontroller Unit Screen&#xff09;&#xff0c;在显示屏背后集成了单片机控制器&#xff0c;因此&#xff0c;MCU屏里面有专用的驱动芯片。驱动芯片如&#xff1a;ILI9488、ILI9341、SSD1963等。驱动芯片里…

7.5 使用MobileNet v3进行图像的区分

MobileNet v3是Google在2019年提出的轻量级卷积神经网络结构,旨在提高在移动设备上的速度和准确性,广泛的用于轻量级网络。 MobileNet v3-Small的网络结构如下,它的输入是224x224的3通道彩色图片。 使用过程如下: 1.创建模型、修改最终分类数量 #1.创建mobilenet_v3_small…

构建面向大模型训练与部署的一体化架构:从文档解析到智能调度

作者&#xff1a;汪玉珠&#xff5c;算法架构师 标签&#xff1a;大模型训练、数据集构建、GRPO、自监督聚类、指令调度系统、Qwen、LLaMA3 &#x1f9ed; 背景与挑战 随着 Qwen、LLaMA3 等开源大模型不断进化&#xff0c;行业逐渐从“能跑通”迈向“如何高效训练与部署”的阶…

PostgreSQL技术大讲堂 - 第86讲:数据安全之--data_checksums天使与魔鬼

PostgreSQL技术大讲堂 - 第86讲&#xff0c;主题&#xff1a;数据安全之--data_checksums天使与魔鬼 1、data_checksums特性 2、避开DML规则&#xff0c;嫁接非法数据并合法化 3、避开约束规则&#xff0c;嫁接非法数据到表中 4、避开数据检查&#xff0c;读取坏块中的数据…

【机器学习】机器学习笔记

1 机器学习定义 计算机程序从经验E中学习&#xff0c;解决某一任务T&#xff0c;进行某一性能P&#xff0c;通过P测定在T上的表现因经验E而提高。 eg&#xff1a;跳棋程序 E&#xff1a; 程序自身下的上万盘棋局 T&#xff1a; 下跳棋 P&#xff1a; 与新对手下跳棋时赢的概率…

Ubuntu20.04 设置开机自启

参考&#xff1a; Ubuntu20.04 设置开机自启_ubuntu进bos系统-CSDN博客

数据库中存储过程的流程语句讲解

一、流程语句讲解 二、总结 一、流程语句讲解 1.1 if语句讲解 语法&#xff1a; IF condition THENstatements; ELSEIF condition THENstatements; ELSEstatements; END IF; 题目示例&#xff1a; # 判断成绩等级 # 输入学生的编号,取出学生的第一门课&#xff0c;然后判断…

kubernetes》》k8s》》ConfigMap 、Secret

configmap官网 ConfigMap是一种 API 对象&#xff0c;使用时&#xff0c; Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。ConfigMap将配置和Pod解耦&#xff0c;更易于配置文件的更改和管理。ConfigMap 并不提供保密或者加密功能。 如果你想存储的数据是机密的…

git在IDEA中使用技巧

git在IDEA中使用技巧 merge和rebase 参考&#xff1a;IDEA小技巧-Git的使用 git回滚、强推、代码找回 参考&#xff1a;https://www.bilibili.com/video/BV1Wa411a7Ek?spm_id_from333.788.videopod.sections&vd_source2f73252e51731cad48853e9c70337d8e cherry pick …