当前位置:首页 > 科技  > 软件

如何用C++实现简单的内存池

来源: 责编: 时间:2024-05-07 09:10:52 259观看
导读内存池(Memory Pool)是计算机编程中一种重要的内存管理技术,它预先分配一块较大的内存区域,并将其划分为多个大小相等的内存块。这种技术旨在减少因频繁申请和释放小块内存而引发的性能开销。下面,我们将结合代码,一步步讲

内存池(Memory Pool)是计算机编程中一种重要的内存管理技术,它预先分配一块较大的内存区域,并将其划分为多个大小相等的内存块。这种技术旨在减少因频繁申请和释放小块内存而引发的性能开销。下面,我们将结合代码,一步步讲解如何实现一个简单的内存池,并分析其工作原理。hzt28资讯网——每日最新资讯28at.com

hzt28资讯网——每日最新资讯28at.com

一、内存池的基本概念

内存池是一种用于动态内存分配的技术,其核心思想是空间换时间。通过预先分配一大块内存,并将其划分为多个小块,内存池能够快速地为程序提供所需的内存,而无需每次都向操作系统申请。这样可以大大减少内存分配和释放的开销,提高程序的运行效率。hzt28资讯网——每日最新资讯28at.com

二、内存池的实现步骤

1. 定义内存池类

首先,我们定义一个名为AdvancedMemoryPool的模板类,它接受一个类型参数T和一个默认大小为100的整数参数PoolSize。这个类将用于管理内存池的分配和回收。hzt28资讯网——每日最新资讯28at.com

template <typename T, size_t PoolSize = 100>class AdvancedMemoryPool {    // ...};

2. 初始化内存池

在类的构造函数中,我们调用expandPool函数来初始化内存池。这个函数将分配一块大小为PoolSize * sizeof(T)的内存,并将其划分为PoolSize个大小为sizeof(T)的内存块。这些内存块的地址被添加到freeChunks_列表中,表示它们是空闲的,可以被分配。hzt28资讯网——每日最新资讯28at.com

AdvancedMemoryPool() {    expandPool();}private:void expandPool() {    char* newBlock = new char[sizeof(T) * PoolSize];    for (size_t i = 0; i < PoolSize; ++i) {        freeChunks_.push_back(reinterpret_cast<T*>(newBlock + i * sizeof(T)));    }    pool_.push_back(newBlock);}

3. 分配内存块

alloc函数用于从内存池中分配一个空闲的内存块。它首先检查freeChunks_列表是否为空。如果为空,则调用expandPool函数来扩展内存池。然后,它从freeChunks_列表中取出一个空闲的内存块,并将其从列表中移除。最后,返回这个内存块的地址。hzt28资讯网——每日最新资讯28at.com

T* alloc() {    std::lock_guard<std::mutex> lock(mutex_); // 确保线程安全    if (freeChunks_.empty()) {        expandPool();    }    T* ptr = freeChunks_.front();    freeChunks_.pop_front();    return ptr;}

这里使用了std::lock_guard来确保在多线程环境下的线程安全。当多个线程同时尝试分配内存时,std::mutex会确保同一时间只有一个线程能够访问内存池。hzt28资讯网——每日最新资讯28at.com

4. 回收内存块

dealloc函数用于回收一个之前分配的内存块。它接受一个指向要回收的内存块的指针,并将这个指针添加到freeChunks_列表中,表示这个内存块现在是空闲的,可以被再次分配。hzt28资讯网——每日最新资讯28at.com

void dealloc(T* ptr) {    assert(ptr != nullptr); // 确保传入的指针不为空    std::lock_guard<std::mutex> lock(mutex_); // 确保线程安全    freeChunks_.push_back(ptr);}

同样,这里也使用了std::lock_guard来确保线程安全。hzt28资讯网——每日最新资讯28at.com

5. 查询内存池状态

我们还提供了两个函数getFreeChunksCount和getUsedChunksCount来查询内存池的状态。这两个函数分别返回空闲和已使用的内存块数量。hzt28资讯网——每日最新资讯28at.com

size_t getFreeChunksCount() const {    std::lock_guard<std::mutex> lock(mutex_); // 确保线程安全    return freeChunks_.size();}size_t getUsedChunksCount() const {    return PoolSize - getFreeChunksCount();}

三、使用内存池

在主函数中,我们创建了一个AdvancedMemoryPool对象,并使用它来分配和回收内存块。通过调用alloc函数,我们可以从内存池中获取一个空闲的内存块,并使用它来存储数据。当我们不再需要这个内存块时,可以调用dealloc函数将其回收回内存池。hzt28资讯网——每日最新资讯28at.com

四、完整代码

#include <iostream>  #include <list>  #include <mutex>  #include <cassert>  #include <cstdlib>    template <typename T, size_t PoolSize = 100>  class AdvancedMemoryPool {  public:      AdvancedMemoryPool() {          expandPool();      }        ~AdvancedMemoryPool() {          std::lock_guard<std::mutex> lock(mutex_);          for (auto& chunk : pool_) {              delete[] reinterpret_cast<char*>(chunk);          }      }        T* alloc() {          std::lock_guard<std::mutex> lock(mutex_);          if (freeChunks_.empty()) {              expandPool();          }            T* ptr = freeChunks_.front();          freeChunks_.pop_front();          return ptr;      }        void dealloc(T* ptr) {          assert(ptr != nullptr);          std::lock_guard<std::mutex> lock(mutex_);          freeChunks_.push_back(ptr);      }        size_t getFreeChunksCount() const {          std::lock_guard<std::mutex> lock(mutex_);          return freeChunks_.size();      }        size_t getUsedChunksCount() const {          return PoolSize - getFreeChunksCount();      }    private:      void expandPool() {          char* newBlock = new char[sizeof(T) * PoolSize];          for (size_t i = 0; i < PoolSize; ++i) {              freeChunks_.push_back(reinterpret_cast<T*>(newBlock + i * sizeof(T)));          }          pool_.push_back(newBlock);      }        mutable std::mutex mutex_;      std::list<T*> freeChunks_;      std::list<char*> pool_;  };    // 使用示例  struct ComplexObject {      int data[100];      // 假设这是一个复杂的对象,需要动态分配  };    int main() {      AdvancedMemoryPool<ComplexObject> pool;        ComplexObject* obj1 = pool.alloc();      ComplexObject* obj2 = pool.alloc();        std::cout << "Free chunks: " << pool.getFreeChunksCount() << std::endl;      std::cout << "Used chunks: " << pool.getUsedChunksCount() << std::endl;        pool.dealloc(obj1);      pool.dealloc(obj2);        std::cout << "Free chunks after deallocation: " << pool.getFreeChunksCount() << std::endl;      std::cout << "Used chunks after deallocation: " << pool.getUsedChunksCount() << std::endl;        return 0;  }

本文链接:http://www.28at.com/showinfo-26-86997-0.html如何用C++实现简单的内存池

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 微服务架构中的挑战及应对方式:Outbox 模式

下一篇: React 合成事件和 JavaScript 事件有什么区别?

标签:
  • 热门焦点
  • K6:面向开发人员的现代负载测试工具

    K6 是一个开源负载测试工具,可以轻松编写、运行和分析性能测试。它建立在 Go 和 JavaScript 之上,它被设计为功能强大、可扩展且易于使用。k6 可用于测试各种应用程序,包括 Web
  • 把LangChain跑起来的三个方法

    使用LangChain开发LLM应用时,需要机器进行GLM部署,好多同学第一步就被劝退了,那么如何绕过这个步骤先学习LLM模型的应用,对Langchain进行快速上手?本片讲解3个把LangChain跑起来
  • 得物效率前端微应用推进过程与思考

    一、背景效率工程随着业务的发展,组织规模的扩大,越来越多的企业开始意识到协作效率对于企业团队的重要性,甚至是决定其在某个行业竞争中突围的关键,是企业长久生存的根本。得物
  • 从零到英雄:高并发与性能优化的神奇之旅

    作者 | 波哥审校 | 重楼作为公司的架构师或者程序员,你是否曾经为公司的系统在面对高并发和性能瓶颈时感到手足无措或者焦头烂额呢?笔者在出道那会为此是吃尽了苦头的,不过也得
  • 雅柏威士忌多款单品价格大跌,泥煤顶流也不香了?

    来源 | 烈酒商业观察编 | 肖海林今年以来,威士忌市场开始出现了降温迹象,越来越多不断暴涨的网红威士忌也开始悄然回归市场理性。近日,LVMH集团旗下苏格兰威士忌品牌雅柏(Ardbeg
  • 自律,给不了Keep自由!

    来源 | 互联网品牌官作者 | 李大为编排 | 又耳 审核 | 谷晓辉自律能不能给用户自由暂时不好说,但大概率不能给Keep自由。近日,全球最大的在线健身平台Keep正式登陆港交所,努力
  • 小米MIX Fold 3配置细节曝光:搭载领先版骁龙8 Gen2+罕见5倍长焦

    这段时间以来,包括三星、一加、荣耀等等有不少品牌旗下的最新折叠屏旗舰都得到了不少爆料,而小米新一代折叠屏旗舰——小米MIX Fold 3此前也屡屡被传
  • OPPO K11搭载长寿版100W超级闪充:26分钟充满100%

    据此前官方宣布,OPPO将于7月25日也就是今天下午14:30举办新品发布会,届时全新的OPPO K11将正式与大家见面,将主打旗舰影像,和同档位竞品相比,其最大的卖
  • 与兆芯合作 联想推出全新旗舰版笔记本电脑开天N7系列

    联想与兆芯合作推出全新联想旗舰版笔记本电脑开天 N7系列。这个系列采用兆芯KX-6640MA处理器平台,KX-6640MA 处理器是采用了陆家嘴架构,16nm 工艺,4 核 4 线
Top