C++内存池(1)理论基础及简单实现

C++开发:内存池 (Memory Pool) 内存池是一种内存管理技术,它预先分配一大块内存,然后在程序运行期间根据需要从这块内存中分配小部分给程序使用,而不是每次都直接向操作系统申请内存。 阅读详情

一、内存池原理

1、我们先用生活中的例子来解释什么是内存池:
    (1)每个月月底钱花完时,或者急需要用钱时,你就打电话给你父母要钱,然后父母把钱通过微信或支付宝转给你。这种方式,每次要用钱时就需要联系你父母,然后你父母再把钱给你,4年大学下来,这里面耗费的时间也精力肯定不少。
    (2)父母一次性给你一大笔钱,你随便用随便花。这样肯定方便多了,这就类似内存池方式。
    所以内存池的思想,就是在真正使用内存之前,预先申请分配一定数量、大小预设的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存,当内存释放后就回归到内存池留作后续的复用。使得内存使用效率得到提升,一般也不会产生不可控制的内存碎片。
2、那么在C++中怎么实现具体的线程池呢?简单地说,需要下面这几个步骤:
    (1)先申请一块连续的内存空间。
    (2)内存节点:含1个数据对象和指向下一个数据对象的指针。每个空闲的内存节点通过指针形成一个链表,链表的每一个内存节点都是一块可供分配的内存空间。
    (3)某个内存节点一旦分配出去,从空闲内存节点链表中移除。
    (4)某个内存节点一旦被释放,将该内存节点重新加入空闲内存节点链表。
    (5)如果一个内存块的所有内存节点分配完毕,若程序继续申请新的对象空间,则会再次申请一个内存块来容纳新的对象。新申请的内存块会加入内存块链表中。

二、用C++实现内存池

1、定义一个内存节点

template<typename T>
struct Node{
    T data;         // 元素
    Node<T>* next;  // 指向下一个节点的指针
};

2、初始化1个内存块

//当前没有空闲节点
if(this->pMemoryHead == nullptr){
    this->pMemoryHead = new Node<T>; //生成新节点
        
    Node<T> *pTemp = this->pMemoryHead; //将数据连接起来
    for(int i = 1; i < blockSize; i++){
         pTemp->next = new Node<T>;
         pTemp = pTemp->next;
    }
    pTemp->next = nullptr;
        
    this->headCount += blockSize; //可用内存节点数
}

3、申请1个对象空间

Node<T> *pTemp = this->pMemoryHead;
pMemoryHead = pMemoryHead->next; //指向下一个未使用的节点

//因为temp指向的是当前将被使用的节点, 把它的next指向前面的被使用节点
pTemp->next = pUsedHead;
pUsedHead = pTemp; //指针指向最新将被使用的节点
this->headCount--;
this->usedCount++;

4、释放对象空间

Node<T> *pFree = (_Node<T>*)p; //释放的节点
Node<T> *pTemp = pUsedHead;

//第一种情况    
if(pTemp == pFree){  //第一个就是

      pUsedHead = pUsedHead->next;
      pTemp->next = pMemoryHead; //将节点重新接到MemoryHead
      pMemoryHead = pTemp;
      
      this->usedCount--;
      this->headCount++;
      
      return;
}

//第二种情况
Node<T> *prev;
while(pTemp != nullptr){        
    if(pTemp == pFree){    
        prev->next = pTemp->next;
        pTemp->next = MemoryHead;
        MemoryHead = pTemp;
            
        this->usedCount--;
        this->headCount++;

        return;
    }
    //前一个节点
    prev = pTemp;
        

    //查询下一个节点
    pTemp = pTemp->next;
}

三、完整代码

1、MemoryPool.h

#include <iostream>
#include <list>
#include <string>

using namespace std;

template<typename T>
struct Node{        //节点
    T data;         //元素
    Node<T>* next;  //指向下一个节点的指针
};

template <typename T, int blockSize = 10>
class MemoryPool{
public:
    MemoryPool();
    ~MemoryPool();
    
    void* allocate();
    int free(void *p);

    int headCount;
    int usedCount;

private:  
    Node<T>* pMemoryHead;  //未使用的节点
    Node<T>* pUsedHead;    //正在使用的节点
};

2、MemoryPool.cpp

#include"MemoryPool.h"
#include<vector>

template <class T, int blockSize>
MemoryPool<T, blockSize>::MemoryPool(){
     this->pMemoryHead = nullptr;
     this->pUsedHead = nullptr;

     this->headCount = 0;
     this->usedCount = 0;
}

template <class T, int BlockSize>
MemoryPool<T, blockSize>::~MemoryPool(){
  Node<T>* ptr;
	while(this->pMemoryHead){
		ptr = this->pMemoryHead->next;
		delete this->pMemoryHead;
		pMemoryHead = ptr;
	}

	while (this->pUsedHead){
		ptr = this->pUsedHead->next;
		delete this->pUsedHead;
		pUsedHead = ptr;
	}
}

template <class T, int blockSize>
void* MemoryPool<T, blockSize>::allocate(){
    if(this->pMemoryHead == nullptr){
        //当没有空闲节点
        this->pMemoryHead = new Node<T>;

        Node<T> *pTemp = this->pMemoryHead;   //将数据连接起来
        for(int i = 1; i < blockSize; i++){
             pTemp->next = new Node<T>;
             pTemp = pTemp->next;
        }
        pTemp->next = nullptr;
        
        this->headCount += blockSize;
    }

    Node<T> *pTemp = pMemoryHead;
    pMemoryHead = pMemoryHead->next;  //指向下一个数据节点

    //将data 挂在到UseHead
    pTemp->next = pUsedHead;
    pUsedHead = pTemp;
    this->headCount--;
    this->usedCount++;

    return reinterpret_cast<void*>(pTemp);
}

template <typename T, int blockSize>
int MemoryPool<T, blockSize>::free(void *p){
     //遍历 UsedHead链表
    Node<T> *pFind = (Node<T>*)p;
    Node<T> *pTemp = pUsedHead;

    if(pTemp == pFind){  //第一个就是
      pUsedHead = pUseHead->next;
      pTemp->next = pMemoryHead;   //将节点重新接到MemoryHead
      pMemoryHead = pTemp;
      
      this->usedCount--;
      this->headCount++;

      return 1;
    }
    
    Node<T> *prev;
    while(pTemp != nullptr){
        if(pTemp == pFind){
            prev->next = pTemp->next;
            pTemp->next = pMemoryHead;
            pMemoryHead = pTemp;

            this->usedCount--;
            this->headCount++;

            return 1;
        }
        
        prev = pTemp;
        // 查下一个节点
        pTemp = pTemp->next;
    }

    return -1;
}

int main(){
    MemoryPool<int, 100> pa;
    vector<int*> ret;
    cout<<"head:"<<pa.headCount<<"use:"<<pa.usedCount<<endl;
    for(int i=0;i<50;i++){
        ret.push_back(reinterpret_cast<int*>(pa.allocate()));
    }
    cout<<"head:"<<pa.headCount<<"use:"<<pa.usedCount<<endl;

    for(int i=0;i<10;i++){
        pa.free(reinterpret_cast<void*>(ret[i]));
    }
    cout<<"head:"<<pa.headCount<<"use:"<<pa.usedCount<<endl;
    return 0;
}

C++项目——高并发内存池 本项目参考了谷歌 tcmalloc 设计模式,设计实现了高并发内存池 阅读详情

相关推荐

C++内存池实现

定义一个结构体用来表示内存块信息,定义节点指针,方便内存块使用与归还,定义内存池标记表示是否属于内存池中的内存单元(当内存池中的内存单元使用完毕后,向系统申请的标记)。添加内存分配类,使用模板的方式传入内存块大小,和内存块个数。

lingshengxiyou的博客 403

C++高并发内存池的设计和实现

C++高并发内存池的设计和实现

m0_60259116的博客 821

C++高性能内存池设计与实现完整项目

内存块是内存池中的最小管理单元,代表一段可供分配的固定大小内存区域。每个块包含两个部分:元数据头(Header)和用户可用区(Payload)。// 指向下一块空闲块的指针参数说明:next:用于构建空闲链表的指针,嵌入在块内部,节省额外元数据开销;BlockBody:计算出的实际可用空间,依赖编译时常量;逻辑分析:此设计采用“指针嵌入式空闲块”策略,即空闲状态下的内存块自身作为链表节点,next字段位于块开头。

weixin_29323977的博客 879

【C++】内存池

【代码】【C++】内存池。

kaiduo123的博客 482

Mac上IDEA的PlantUML插件报错‘找不到Graphviz’?手把手教你用Homebrew搞定(附阿里云镜像避坑)

本文详细解决了Mac上IDEA的PlantUML插件报错‘找不到Graphviz’的问题,通过Homebrew安装Graphviz并配置阿里云镜像源,特别针对Apple Silicon芯片用户提供了优化方案。文章还涵盖了IDEA中PlantUML插件的正确配置和常见问题排查,帮助开发者高效使用PlantUML进行UML图表设计。

weixin_42619742的博客 468

基于STM32与FPGA Cyclone IV的FSMC高速数据通信实战解析

本文详细解析了基于STM32的FSMC接口与FPGA Cyclone IV实现高速并行数据通信的实战方案。通过将FPGA模拟为SRAM设备,构建了MCU与FPGA之间的高速数据通道,并深入探讨了硬件连接、STM32软件配置、FPGA逻辑设计及性能优化等关键步骤,为图像处理、高速采集等需要大数据量交换的嵌入式应用提供了稳定高效的通信解决方案。

swift5iosmith的博客 294

C++内存池实战指南:原理、实现与最佳实践

本文深入探讨了C++内存池技术的原理与实现。内存池通过预分配和复用内存块来解决标准内存分配的性能问题,包括高频分配损耗、堆内存碎片化和多线程竞争等痛点。文章详细介绍了固定大小和可变大小内存池的设计思路与实现方法,重点解析了空闲链表管理、内存对齐等关键技术。同时对比了tcmalloc、jemalloc等工业级内存池库的特点,提供了替换标准分配器的最佳实践。最后总结了内存池使用中的常见问题与解决方案,强调要根据实际场景选择合适的方案,在性能与可维护性之间取得平衡。内存池是提升C++程序性能的重要技术,适用于高并

物换星移几度秋 1174

从平面到立体:一张图看懂MOSFET、FinFET到GAAFET的演变史(附结构对比图)

本文深入解析了半导体晶体管从平面MOSFET到三维FinFET,再到全环绕栅极GAAFET的技术演进历程。通过结构对比图和物理原理分析,揭示了每一次创新如何解决短沟道效应等关键挑战,推动芯片性能提升。特别关注GAAFET作为最新技术突破的架构特点和性能优势。

weixin_30892037的博客 693

图文结合纯c手写内存池

本文从零到一,手把手实现一个内存池。

清风 4149

动手学Moveit2 | 运行配置好的机械臂功能demo

通过这个小demo你可以直观的感受moveit2的强大,但还有很多需要我们探索的,比如机械臂是如何规划的,规划的过程中如何结合环境信息,规划的时候机械臂如何求解,如何和真实的机械臂对接等等,这些都需要你来进一步探索,今天就到这里,明天给大家秀一下小仙女焊的fishbot运控板。

生活不止眼前的苟且 8880

科研软件|Adobe Photoshop 2024 (PS 2024)

科研软件|Adobe Photoshop 2024 (PS 2024)

m0_55499682的博客 5510

C++高并发内存池实战:初步了解

本文深入探讨了C++高并发内存池的实现原理与技术细节。首先介绍了高并发系统的特点与内存池的核心概念,包括预分配内存、固定大小内存块等关键特性。重点分析了定长内存池的实现方法,详细展示了跨平台的系统调用封装(Malloc)、内存分配(New)与释放(Delete)接口的实现代码。文章最后勾勒出高并发内存池的三层架构:线程级缓存ThreadCache减少锁竞争,中心缓存CentralCache作为中介层,以及直接与操作系统交互的PageCache。该架构通过分层设计有效提升了多线程环境下的内存分配效率,为后续深

WildPointer的博客 1234

uniapp [全端兼容] - 实现接入集成高德地图搜索地址及选择位置功能,搜索框检索选择地点并返回经纬度及详细省市区县街道地址,用户搜索历史及清空历史记录,选择地址自动获取周边位置列表/地图移动选点

uni-app,高德地图,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,Uniapp高德地图,在地图上选择或搜索指定地点,打开地图选择位置,关联地址搜索,输入地址返回附近地址列表,uniApp高德地图地址搜索,搜索框历史记录,关键字搜索,周边查询,搜索位置,uniapp对接高德实现搜索出现地址以及保存搜索记录,集成高德地图,实现精准位置选点功能,获取当前定位城市,如何实现搜索功能,获取省份城市区街道详细地址经纬度,移动选点标记位置,在地图上进行选择位置选点、搜索

🏆 前端领域优质创作者 1万+

深入剖析 C++ 内存池:从原理到实现

维度数据核心代码量210+性能提升单次分配 5.6 倍,批量分配 10.4 倍支持功能构造/析构、线程安全、批量分配、内存监控、STL适配。

2301_80196447的博客 315

极验验证码: 一点即过验证(鼠标轨迹分析)

2、第一个验证接口分析(第一个w值还原) 3、第二个验证接口(第二个w值还原)这里定位w生成跟上篇文章一样,就不展开了;主要分析tt值(鼠标轨迹)的生成逻辑

qq_49268524的博客 1009

lammps教程:ovito免费输出高清图片方法

基本原理是调用ovito软件包中的TachyonRenderer模块,该模块可实现Tachyon渲染,达到和ovito 2.9 Tachyon完全相同的效果。这种方法在后来的ovito版本中已经不能使用,但是ovito 2.9版本在后处理方面功能较少,使用起来也不是特别方便。在之前的推文中,曾介绍过使用ovito 2.9版本更换Tachyon渲染器实现高清图片的输出。这个方法只需要配置ovito模块即可,完全免费,不需要购买ovito pro版。具体的配置参数可到ovito官网查询。大家好,我是小马老师。

lammps_jiayou的博客 2766

高并发内存池 设计定长内存池(1)

Hello,今天我再次开启新篇,这里想为大家撰写一下项目【高并发内存池】,站在现在的上帝视角,我可以很明确的说这是一个非常有趣的项目难度也不小,主要集中在多线程与线程安全那里,并且本身涉及内存的项目就不是很好调试说多了都是泪,但是事不宜迟,就这样开始我们的第一篇吧!但是在正式开始讲解项目内容的时候,我们先聚焦这个项目本身,看看它是什么样的架构,什么样的原理,什么样的用途~~我记得这不是我第一次提到过池化技术这个词,应该在 C++篇 和 Linux篇 都有提一嘴。

tan180°的博客 1011

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

101 C++内存高级话题 内存池概念,代码实现和详细分析

二 针对一个类的内存池实现演示代码。一 内存池的概念和实现原理概述。三,内存池代码后续说明。

hunandede的博客 714

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

我的C++内存池学习之路:从理论到实战

每个空闲块包含块大小和指向下一个空闲块的指针,分配时遍历链表找到合适的块,释放时把块插回链表。阿贝云的免费云服务器虽然配置基础,但SSD硬盘读写流畅,BGP线路延迟稳定,对学习者来说完全够用。需要校验块是否已在链表中,或采用更稳健的设计:释放时把块大小恢复到释放前的值。我选择在分配时把块大小保存在块头的第一个word中,释放时不做修改,这样块大小始终有效。数组作为内存池,每个空闲块头部两个word:第一个存块大小(按word计),第二个存下一个空闲块的指针。的地址,但没保存块大小。把块插入链表时只保存了。

2601_95983539的博客 198

掌握这7种C++内存池技术,轻松驾驭大规模量子计算仿真

掌握C++内存池技术,高效解决大规模量子计算仿真中的内存优化难题。适用于高频内存分配场景,提升性能30%以上。七种实用方法详解,显著降低碎片率,值得收藏。

PixelGlow的博客 966

C++实现高并发内存池:仿tcmalloc

详解多线程高并发内存池的C++实现:仿tcmalloc

2402_86037826的博客 917

内存泄漏终结方案,基于C++的固定大小内存池全实现路径

解决频繁内存分配导致的性能瓶颈,本文深入解析C++内存池实现(固定大小块),适用于高频小对象分配场景。通过预分配内存块、高效管理空闲链表,显著提升分配速度并避免碎片。代码可复用,值得收藏。

AlgoFun的博客 378

探秘 C++ 内存管理:从虚拟内存到内存池的深度解析与实战应用

本文深入剖析了计算机内存管理的核心知识,特别是 C++ 程序中的内存运用。首先,详细介绍了虚拟内存与物理内存的概念,阐述了虚拟内存解决内存资源浪费、进程数据安全和程序运行地址错误等问题的原理,以及通过 MMU、页表和内存映射文件实现虚拟到物理内存的映射方式。接着,讲解了关键的内存概念,如 Swap、Buffers 和 Cache,以及它们在数据处理中的重要作用。在 C++ 程序内存方面,全面阐述了内存布局、操作方法、对齐规则、内存泄漏问题及智能指针的使用。最后,着重介绍了内存池的基本概念、实现原理、代码实现

m0_73359068的博客 2080

C++高性能内存池实现全解析,来自2025全球技术大会的一线经验

掌握高性能C++内存池设计精髓,解决频繁分配导致的性能瓶颈。源自2025全球C++及系统软件技术大会:高性能C++内存分配策略分享,涵盖高并发场景下的对象池、内存对齐与无锁分配实现,显著提升系统响应速度与资源利用率,值得收藏。

AlgoPerch的博客 854

C/C++内存管理详解:从基础原理到自定义内存池原理

C/C++内存管理,C语言中动态内存管理方式,C++内存管理方式,new/delete,关于异常的调试技巧,operator new与operator delete,定位new,内存池相关概念,malloc/free和/new/delete的区别

2502_91499791的博客 845

[C++ 高并发内存池] 内存管理基础与问题分析

本章深入探讨了内存管理的基础知识、核心问题及高并发挑战。首先介绍了程序内存布局,重点分析了堆区管理机制。通过简化malloc实现,揭示了传统内存管理的性能瓶颈:线性搜索导致O(n)复杂度,全局锁引发线程竞争。其次详细解析了内存碎片问题,包括内部碎片(由内存对齐和分配粒度造成)和外部碎片(空闲内存不连续导致)。最后讨论了高并发场景下的挑战,如锁竞争、缓存失效和伪共享问题。这些分析为后续内存池优化技术奠定了基础,旨在解决传统内存管理的关键性能问题。

kevin_blog 1029
上一篇: 掌握std::move和std::forward
下一篇: 智能指针解读(1)
老蔡编程
博客等级 码龄23年 48粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值