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

设计定长的内存池

目录

  • 定长内存池设计
    • 设计思路
      • 具体实现
        • 定长内存池初始化
          • T*New()申请内存
            • 代码
          • void Delete(T* obj)回收内存
            • 代码
          • 设计的总代码
          • 测试代码
  • Objectpool.h文件代码
  • test.cpp文件代码
  • 拓展windows和Linux下如何直接向堆申请页为单位的大块内存:

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录
🤠🤠🤠 高并发内存池项目

定长内存池设计

设计思路

申请一大块内存,用一个指针指向申请的内存,这里的难点是内存释放,因为我们申请的是一块很大的内存,而使用的时候都是将这一大块内存切成一小块一小块的用,而用完后释放我们不可以直接将他还给系统,因为释放的内存太小了,如果还给系统就会出现内存碎片的问题,所以我们是要将需要释放的内存管理起来,当他们都释放后再归还内存,这里的管理方式就是用一个链表将内存管理起来
在这里插入图片描述
由于是定长内存池,这里的定长就是切固定大小的内存

具体实现

定长内存池初始化

首先我们需要一个类

class Objectpool
{};

由于是定长内存池,所以类里面一点要有一个指针指向申请的内存空间,为了方便切割内存我们使用char*_memory,因为char是可以精确到1个字节1个字节的切割比较方便,如果是int的话那么我们要切割的长度就是4的倍数
此外因为申请内存是固定的我们可以用非类型的模版参数template<size_t N>表示我们申请的内存是一个固定大小为N
当然我们也可以用template表示ObjectPool每次获取的对象都是一个T对象,T的大小是固定的,这里我们选择的是用template

template<class T>
class ObjectPool
{char* _memory=nullptr;
};

我们还需要考虑内存回收
在这里插入图片描述
当我们需要切割内存时_memory需要往后移动
在这里插入图片描述

在这里插入图片描述
当切割后的内存用完后需要回收我们需要用一个链表将他们串起来
在这里插入图片描述
在这里插入图片描述
可是现在有一个问题我们应该怎么样才能将他们串起来,我们是否需要再定义一个结构体将他们链接起来呢?

其实是不需要的,我们可以直接在内存当中修改,将后面的内存块地址存到前一个内存块当中,但是这里有一个要求就是32位下的指针大小是4个字节,而64位下的指针大小是8个字节,也就意味着当我们要存一个内存块的空间时,32位下内存块至少要有4个字节,而64位则至少要有8个字节

在32位下对于一个内存块有100字节我们则需要将他的头4个字节进行修改保存下一块内存的地址
在这里插入图片描述

T*New()申请内存

申请内存我们需要先看_memory是否为空,如果_memory为空的话那么就需要申请内存

T* New()
{if (_memory==nullptr)//剩余内存不够一个对象大小是重新开大块空间{_memory =(char*) malloc(128 * 1024);//128kbif (_memory == nullptr){throw std::bad_alloc();}}T* obj = (T*)_memory;_memory += sizeof(T);return obj;
}

如果申请后_memory仍为空那么就抛异常,反之就让一个对象obj指向申请内存的空间
_memory += sizeof(T)就表示的切割空间,让_memory切割 sizeof(T)大小的空间
在这里插入图片描述

这里有一个问题就是_memory走到最后的时候,如果_memory继续+= sizeof(T)就会造成越界,因为申请的内存以及用完了,而_memory现在在访问的是别的空间
在这里插入图片描述
在这里插入图片描述
为了解决这个问题我们还需要有一个remainBytes去记录还剩多少空间,当remainBytes<sizeof(T)的时候就意味着剩下的空间以及不足以支持我们继续切割了,可能需要重新申请一块空间

为什么是可能需要重新申请一块空间呢,因为_freeList是回收释放的内存,如果_freeList中有回收了的内存,那么这些内存是可以继续重复利用的
所以一开始需要一个指针next保存_freeList前面记录下来的位置,然后让obj指向_freeList,再让_freeList=next

	T* obj = nullptr;if (_freeList){void* next = *((void**))_freeList);obj = (T*)_freeList;//因为obj是T*,所以_freeList也要强转_freeList = next;}

void* next = * ((void**))_freeList)这段代码会在下面部分解释
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
还有一个问题就是sizeof(T)大小问题,因为这是一个类模版,如果T是char类型的话他的内存是小于4个字节的,int类型的话也就刚好4个字节,但是在64位下是不够的,所以需要判断sizeof(T) < sizeof(void*) ,表示T的内存大小是否小于一个指针,如果小于的话就要更改切割内存的大小
最后我们还需要对我们创造的对象进行初始化
这里用定位new显示调用T的构造函数初始化new(obj)T

代码
	T* New(){T* obj = nullptr;if (_freeList){void* next = *((void**))_freeList);obj =(T*) _freeList;_freeList = next;}else{if (_remainBytes < sizeof(T))//剩余内存不够一个对象大小是重新开大块空间{_remainBytes = 128 * 1024;_memory = (char*)malloc(_remainBytes);//128kbif (_memory == nullptr){throw std::bad_alloc();}}obj = (T*)_memory;size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);//因为T是一个类模版,当T是char或int时可能会导致内存不足以存储一个地址_memory += objSize;_remainBytes -= objSize;}new(obj)T;//定位new显示调用T的构造函数初始化return obj;}
void Delete(T* obj)回收内存

在最开始的时候_freeList是指向的空
在这里插入图片描述
当第一次有空间回收时,我们要让空间的前4个字节存空地址,具体办法就是让传入的指针强转成int*,那么我们对int进行解引用将前4个字节更改为nullptr就可以实现了
在这里插入图片描述
但是这里有一个问题就是int
只有4个字节,这种方法只适用于32位下,在64位下是不行的
当然我们可以用if语句判断一个指针的大小,然后再进行细分也是可以的
下面有更简单的方式就是将obj强转成void**,也就是二级指针(其他类型的二级指针也是可以的,主要用的就是二级指针转换成一级指针的空间大小是4/8个字节),然后我们对他解引用,*(void**)obj = nullptr

上面是解决第一次内存块回收的问题,下面是解决多次回收的问题
在这里插入图片描述

多个内存块回收我们选择用头插的方式串起来,因为尾插效率太低
在这里插入图片描述
首先还是要让新的内存块保存_freeList指向的地址,然后让_freeList指向新的内存块
在这里插入图片描述
在这里插入图片描述

void Delete(T* obj)
{if (_freeList==nullptr){_freeList = obj;*(void**)obj = nullptr;}else{*(void**)obj = _freeList;_freeList = obj;}
}

我们发现上面代码中

*(void**)obj = _freeList;_freeList = obj;

这段代码是适用于所有情况的
一开始_freeList=nullptr
在这里插入图片描述
让obj前4/8个字节保存_freeList
在这里插入图片描述
然后让_freeList指向obj
在这里插入图片描述
即使有新回收的也是适用的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码
void Delete(T* obj)
{obj->~T();//显示调用析构函数*(void**)obj = _freeList;_freeList = obj;
}
设计的总代码
template<class T>
class ObjectPool
{
public:T* New(){T* obj = nullptr;if (_freeList){void* next = *((void**)_freeList);obj =(T*) _freeList;_freeList = next;}else{if (_remainBytes < sizeof(T))//剩余内存不够一个对象大小是重新开大块空间{_remainBytes = 128 * 1024;_memory = (char*)malloc(_remainBytes);//128kbif (_memory == nullptr){throw std::bad_alloc();}}obj = (T*)_memory;size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);_memory += objSize;_remainBytes -= objSize;}new(obj)T;return obj;}void Delete(T* obj){obj->~T();*(void**)obj = _freeList;_freeList = obj;}
private:char* _memory = nullptr;//指向大块内存的指针void* _freeList = nullptr;//还回过程中链接的自由链表头指针size_t _remainBytes = 0;//大块内存切割过程中的剩余字节数
};
测试代码
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;
}

Objectpool.h文件代码

#include<iostream>
#include<vector>
#include<time.h>
using std::cout;
using std::endl;
template<class T>
class ObjectPool
{
public:T* New(){T* obj = nullptr;if (_freeList){void* next = *((void**)_freeList);obj =(T*) _freeList;_freeList = next;}else{if (_remainBytes < sizeof(T))//剩余内存不够一个对象大小是重新开大块空间{_remainBytes = 128 * 1024;_memory = (char*)malloc(_remainBytes);//128kbif (_memory == nullptr){throw std::bad_alloc();}}obj = (T*)_memory;size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);_memory += objSize;_remainBytes -= objSize;}new(obj)T;return obj;}void Delete(T* obj){obj->~T();*(void**)obj = _freeList;_freeList = obj;}
private:char* _memory = nullptr;//指向大块内存的指针void* _freeList = nullptr;//还回过程中链接的自由链表头指针size_t _remainBytes = 0;//大块内存切割过程中的剩余字节数
};
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;
}

test.cpp文件代码

#include"Objectpool.h"
int main()
{TestObjectPool();return 0;  
}

拓展windows和Linux下如何直接向堆申请页为单位的大块内存:

VirtualAlloc
Linux进程分配内存的两种方式–brk() 和mmap()

相关文章:

设计定长的内存池

目录 定长内存池设计设计思路具体实现定长内存池初始化T*New()申请内存代码 void Delete(T* obj)回收内存代码 设计的总代码测试代码 Objectpool.h文件代码test.cpp文件代码拓展windows和Linux下如何直接向堆申请页为单位的大块内存&#xff1a; 感谢各位大佬对我的支持,如果我…...

【动手学电机驱动】 STM32-FOC(7)基于 MCSDK6.0 控制与调试速度环

STM32-FOC&#xff08;1&#xff09;STM32 电机控制的软件开发环境 STM32-FOC&#xff08;2&#xff09;STM32 导入和创建项目 STM32-FOC&#xff08;3&#xff09;STM32 三路互补 PWM 输出 STM32-FOC&#xff08;4&#xff09;IHM03 电机控制套件介绍 STM32-FOC&#xff08;5&…...

无人机飞手考证,地面站培训技术详解

无人机飞手考证及地面站培训技术涉及多个关键方面&#xff0c;以下是对这些方面的详细解析&#xff1a; 一、无人机飞手考证流程与要求 1. 证书类型 民用无人机驾驶员证书&#xff1a;这是国家民航局颁发的无人机操作人员资质证书&#xff0c;分为视距内驾驶员、超视距驾驶员…...

音视频入门基础:MPEG2-TS专题(3)——TS Header简介

注&#xff1a;本文有部分内容引用了维基百科&#xff1a;https://zh.wikipedia.org/wiki/MPEG2-TS 一、引言 本文对MPEG2-TS格式的TS Header进行简介。 进行简介之前&#xff0c;请各位先下载MPEG2-TS的官方文档。ITU-T和ISO/IEC都分别提供MPEG2-TS的官方文档。但是ITU提供的…...

Sam Altman:年底将有重磅更新,但不是GPT-5!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…...

基于物联网的智能超市快速结算系统

摘 要 当今社会的商品层出不穷&#xff0c;人们因为越来越多大型仓储超市的出现使得生活更加便利&#xff0c;但许多随之而来的新问题也给人们带来了许多的不便&#xff0c;例如商家一直被更换标签不及时、货物丢失、超市内物品更换处理不及时、超市内人流高峰期人流控制不得…...

241111.学习日志——[CSDIY] Cpp零基础速成 [00]

CSDIY&#xff1a;这是一个非科班学生的努力之路&#xff0c;从今天开始这个系列会长期更新&#xff0c;&#xff08;最好做到日更&#xff09;&#xff0c;我会慢慢把自己目前对CS的努力逐一上传&#xff0c;帮助那些和我一样有着梦想的玩家取得胜利&#xff01;&#xff01;&…...

湘潭大学软件工程算法设计与分析实验-模拟退火算法

文章目录 写在前面代码分析 写在前面 总共是要四份代码&#xff0c;好像都是实现背包问题&#xff0c;前面三个都比较简单直观&#xff0c;朋友上周在机房给我讲解了一下之后&#xff0c;我大概弄清楚了&#xff0c;这周好像是最后一次算法课了&#xff0c;所以明天我得把剩下…...

Three.js 零基础+概念理解

文章目录 一、Three.js基础概念&#xff08;一&#xff09;什么是Three.js&#xff08;二&#xff09;核心对象&#xff08;三&#xff09;几何体&#xff08;Geometries&#xff09;和材质&#xff08;Materials&#xff09; 二、基础实例应用&#xff08;一&#xff09;创建一…...

c#使用COM接口设置excel单元格宽高匹配图片,如何计算?

c#使用COM接口设置excel单元格宽高如何换算 在实际工作中&#xff0c;经常需要在excel中插入图片。并设置单元格与图片对齐。但是excel单元格的宽度和高度使用不同的单位。单元格的宽度以字符宽度为单位&#xff0c;而高度以点为单位。如果按照实际值来设置&#xff0c;例如设…...

Excel模板下载\数据导出

pom <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version> </dependency><build><resources><resource><!--将xlsx打包到jar--><director…...

Vite初始化Vue3+Typescrpt项目

初始化项目 安装 Vite 首先&#xff0c;确保你的 Node.js 版本 > 12.0.0。然后在命令行中运行以下命令来创建一个 Vite Vue 3 TypeScript 的项目模板&#xff1a; npm init vitelatest进入项目目录 创建完成后&#xff0c;进入项目目录&#xff1a; cd vue3-demo启动…...

深入剖析【C++继承】:单一继承与多重继承的策略与实践,解锁代码复用和多态的编程精髓,迈向高级C++编程之旅

​​​​​​​ &#x1f31f;个人主页&#xff1a;落叶 &#x1f31f;当前专栏: C专栏 目录 继承的概念及定义 继承的概念 继承定义 定义格式 继承基类成员访问⽅式的变化 继承类模板 基类和派⽣类间的转换 继承中的作⽤域 隐藏规则 成员函数的隐藏 考察继承【作⽤…...

地级市能源消耗数据(2006至2021)含原始数据、计算过程、计算结果-最新出炉

能源消耗数据分析-2006-2021年地级市能源消耗数据&#xff08;原始数据计算过程结果&#xff09; 下载链接-点它&#x1f449;&#x1f449;&#x1f449;&#xff1a;https://download.csdn.net/download/qq_67479387/89911272 全国能源消耗概况 2021年&#xff0c;我国单位…...

MySQL技巧之跨服务器数据查询:基础篇-A数据库与B数据库查询合并

MySQL技巧之跨服务器数据查询&#xff1a;基础篇-A数据库与B数据库查询合并 上一篇已经描述&#xff1a;借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的链接名: MY_ODBC_MYSQL 以…...

AutoSAR CP DoIP规范导读

主要功能和用途 诊断通信协议实现 遵循标准&#xff1a;遵循ISO 13400 - 2标准&#xff0c;实现了诊断通信在IP网络上的传输协议和网络层服务&#xff0c;包括数据封装、传输、路由等功能。 多种消息支持 车辆识别与公告&#xff1a;能够进行车辆识别请求和响应&#xff0c;…...

Window下PHP安装最新sg11(php5.3-php8.3)

链接: https://pan.baidu.com/s/10yyqTJdwH_oQJnQtWcwIeA 提取码: qz8y 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 (链接失效联系L88467872) 1.下载后解压文件&#xff0c;将对应版本的ixed.xx.win文件放进php对应的ext目录下&#xff0c;如图所示 2.修改ph…...

2024华为OD机试真题---中文分词模拟器

华为OD机试中的中文分词模拟器题目&#xff0c;通常要求考生对给定的不包含空格的字符串进行精确分词。这个字符串仅包含英文小写字母及英文标点符号&#xff08;如逗号、分号、句号等&#xff09;&#xff0c;同时会提供一个词库作为分词依据。以下是对这类题目的详细解析 一…...

Kubernetes网络揭秘:从DNS到核心概念,一站式综述

文章目录 一.overlay vs underlayL2 underlayL3 underlay 二、calico vs flannel2.1 calico架构2.2 flannel架构 三、iptables四、Vxlan五、kubernetes网络架构综述六、DNS七、Kubernetes域名解析策略 一.overlay vs underlay overlay网络是在传统网络上虚拟出一个虚拟网络&am…...

C#封装EPPlus库为Excel导出工具

1&#xff0c;添加NUGet包 2&#xff0c;封装工具类 using OfficeOpenXml; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection;namespace GMWPF.utils {public class ExcelUtil<T>{/// <summary>///…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...