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

学懂C++(四十四):C++ 自定义内存管理的深入解析:内存池与自定义分配器

目录

1. 内存池(Memory Pool)

概念

模型

特点

核心点

实现

适用场景

经典示例实现

代码解析

2. 自定义分配器(Custom Allocators)

概念

模型

特点

核心点

实现

适用场景

经典示例实现

代码解析

高级自定义分配器示例

代码解析

总结


        C++作为一种高性能编程语言,在处理内存管理方面提供了极大的灵活性。默认情况下,C++使用操作系统提供的内存分配和释放机制(如newdeletemallocfree)。然而,在某些高性能或特定需求的应用中,默认的内存管理机制可能无法满足需求。这时,自定义内存管理技术,如内存池(Memory Pool)和自定义分配器(Custom Allocators),可以提供更高效、更灵活的内存管理方案。

        本文将详细介绍内存池和自定义分配器在C++中的应用,包含其概念、模型、特点、核心点、实现方法、适用场景,以及经典示例代码和详细解析。

1. 内存池(Memory Pool)

概念

        内存池是一种自定义内存管理机制,通过预分配一大块内存并将其划分成多个固定大小的块,从而实现快速的内存分配和释放。这种技术特别适用于频繁分配和释放相同大小对象的场景。

模型

  • 预分配内存块:一次性分配一大块连续的内存。
  • 分割内存块:将大块内存划分为多个固定大小的小块。
  • 空闲块管理:维护一个空闲块的列表,用于快速分配和释放内存。

特点

  • 高效性:内存分配和释放操作可以在常数时间内完成。
  • 减少碎片:通过固定大小的块减少内存碎片问题。
  • 预分配:内存池一次性分配大块内存,减少多次分配带来的开销。

核心点

  • 预先分配足够大的内存块。
  • 维护空闲块列表,实现快速分配和释放。

实现

#include <iostream>
#include <vector>
#include <cassert>class MemoryPool
{
private:struct Block{Block* next;};Block* freeBlocks; // 空闲块链表头指针std::vector<void*> pool; // 用于存储内存块的指针数组void allocatePool(size_t blockSize, size_t blockCount){// 分配一大块连续内存void* newPool = operator new(blockSize * blockCount);pool.push_back(newPool);Block* head = static_cast<Block*>(newPool);freeBlocks = head;// 初始化空闲块链表for (size_t i = 1; i < blockCount; ++i){head->next = reinterpret_cast<Block*>(reinterpret_cast<char*>(head) + blockSize);head = head->next;}head->next = nullptr;}public:MemoryPool(size_t blockSize, size_t blockCount){allocatePool(blockSize, blockCount);}~MemoryPool(){// 释放所有内存块for (void* ptr : pool){operator delete(ptr);}}void* allocate(){if (!freeBlocks){// 如果没有空闲块,则分配新的内存池throw std::bad_alloc();}// 从空闲块链表中取出一个块Block* block = freeBlocks;freeBlocks = freeBlocks->next;return block;}void deallocate(void* ptr){// 将块返回到空闲块链表中Block* block = static_cast<Block*>(ptr);block->next = freeBlocks;freeBlocks = block;}
};

适用场景

  • 高性能应用:如游戏开发中的对象池、网络服务器的连接管理等。
  • 频繁分配和释放相同大小对象:如内存块、节点对象等。

经典示例实现

#include <iostream>
#include <vector>
#include <cassert>class MemoryPool
{
private:struct Block{Block* next;};Block* freeBlocks; // 空闲块链表头指针std::vector<void*> pool; // 用于存储内存块的指针数组void allocatePool(size_t blockSize, size_t blockCount){// 分配一大块连续内存void* newPool = operator new(blockSize * blockCount);pool.push_back(newPool);Block* head = static_cast<Block*>(newPool);freeBlocks = head;// 初始化空闲块链表for (size_t i = 1; i < blockCount; ++i){head->next = reinterpret_cast<Block*>(reinterpret_cast<char*>(head) + blockSize);head = head->next;}head->next = nullptr;}public:MemoryPool(size_t blockSize, size_t blockCount){allocatePool(blockSize, blockCount);}~MemoryPool(){// 释放所有内存块for (void* ptr : pool){operator delete(ptr);}}void* allocate(){if (!freeBlocks){// 如果没有空闲块,则分配新的内存池throw std::bad_alloc();}// 从空闲块链表中取出一个块Block* block = freeBlocks;freeBlocks = freeBlocks->next;return block;}void deallocate(void* ptr){// 将块返回到空闲块链表中Block* block = static_cast<Block*>(ptr);block->next = freeBlocks;freeBlocks = block;}
};class Widget
{
public:int x, y, z;Widget(int a, int b, int c) : x(a), y(b), z(c) {}void display(){std::cout << "Widget(" << x << ", " << y << ", " << z << ")" << std::endl;}// 重载new操作符static void* operator new(size_t size){return pool.allocate();}// 重载delete操作符static void operator delete(void* ptr){pool.deallocate(ptr);}private:static MemoryPool pool;
};// 初始化静态内存池
MemoryPool Widget::pool(sizeof(Widget), 10);int main()
{std::vector<Widget*> widgets;// 分配Widget对象for (int i = 0; i < 10; ++i){widgets.push_back(new Widget(i, i + 1, i + 2));}// 显示Widget对象for (Widget* widget : widgets){widget->display();}// 释放Widget对象for (Widget* widget : widgets){delete widget;}return 0;
}

代码解析

  1. MemoryPool:实现内存池管理,包括分配和释放内存块。
  2. Widget:示例对象类,重载了newdelete操作符以使用内存池进行内存管理。
  3. main函数:展示了如何使用内存池分配和释放Widget对象。

2. 自定义分配器(Custom Allocators)

概念

自定义分配器是C++标准库(STL)中的一种机制,允许开发者控制容器的内存分配策略。通过自定义分配器,开发者可以替换默认的内存分配方式,以满足特定的性能需求或内存管理策略。

模型

  • 分配器类:实现内存分配和释放的接口(如allocatedeallocate方法)。
  • 容器类:使用自定义分配器进行内存管理。

特点

  • 灵活性:开发者可以完全控制内存分配和释放。
  • 可扩展性:可以根据具体需求实现不同的内存管理策略。

核心点

  • 实现分配器类,提供allocatedeallocate方法。
  • 在容器中使用自定义分配器。

实现

#include <iostream>
#include <memory>
#include <vector>template <typename T>
class CustomAllocator
{
public:using value_type = T;CustomAllocator() = default;template <typename U>CustomAllocator(const CustomAllocator<U>&) {}T* allocate(std::size_t n){std::cout << "Allocating " << n << " element(s)" << std::endl;return static_cast<T*>(::operator new(n * sizeof(T)));}void deallocate(T* ptr, std::size_t n){std::cout << "Deallocating " << n << " element(s)" << std::endl;::operator delete(ptr);}
};template <typename T, typename U>
bool operator==(const CustomAllocator<T>&, const CustomAllocator<U>&)
{return true;
}template <typename T, typename U>
bool operator!=(const CustomAllocator<T>&, const CustomAllocator<U>&)
{return false;
}

适用场景

  • 高性能应用:如游戏开发中的对象池、实时系统的内存管理等。
  • 特定内存管理需求:如内存对齐、内存池管理等。

经典示例实现

#include <iostream>
#include <memory>
#include <vector>// 自定义分配器类
template <typename T>
class CustomAllocator
{
public:using value_type = T;CustomAllocator() = default;template <typename U>CustomAllocator(const CustomAllocator<U>&) {}T* allocate(std::size_t n){std::cout << "Allocating " << n << " element(s)" << std::endl;return static_cast<T*>(::operator new(n * sizeof(T)));}void deallocate(T* ptr, std::size_t n){std::cout << "Deallocating " << n << " element(s)" << std::endl;::operator delete(ptr);}
};template <typename T, typename U>
bool operator==(const CustomAllocator<T>&, const CustomAllocator<U>&)
{return true;
}template <typename T, typename U>
bool operator!=(const CustomAllocator<T>&, const CustomAllocator<U>&)
{return false;
}int main()
{// 使用自定义分配器的vector容器std::vector<int, CustomAllocator<int>> vec;// 添加元素for (int i = 0; i < 5; ++i){vec.push_back(i);}// 显示元素for (int i : vec){std::cout << i << std::endl;}return 0;
}

代码解析

  1. CustomAllocator:实现自定义分配器,包括allocatedeallocate方法。
  2. operator==operator!=:定义分配器的比较操作符。
  3. main函数:展示了如何使用自定义分配器创建vector容器,并进行元素的添加和显示。

高级自定义分配器示例

#include <iostream>
#include <memory>
#include <vector>// 高级自定义分配器类
template <typename T>
class AdvancedAllocator
{
public:using value_type = T;AdvancedAllocator() = default;template <typename U>AdvancedAllocator(const AdvancedAllocator<U>&) {}T* allocate(std::size_t n){std::cout << "Advanced Allocator: Allocating " << n << " element(s)" << std::endl;return static_cast<T*>(::operator new(n * sizeof(T)));}void deallocate(T* ptr, std::size_t n){std::cout << "Advanced Allocator: Deallocating " << n << " element(s)" << std::endl;::operator delete(ptr);}template <typename U, typename... Args>void construct(U* p, Args&&... args){std::cout << "Advanced Allocator: Constructing element" << std::endl;::new((void*)p) U(std::forward<Args>(args)...);}template <typename U>void destroy(U* p){std::cout << "Advanced Allocator: Destroying element" << std::endl;p->~U();}
};template <typename T, typename U>
bool operator==(const AdvancedAllocator<T>&, const AdvancedAllocator<U>&)
{return true;
}template <typename T, typename U>
bool operator!=(const AdvancedAllocator<T>&, const AdvancedAllocator<U>&)
{return false;
}int main()
{// 使用高级自定义分配器的vector容器std::vector<int, AdvancedAllocator<int>> vec;// 添加元素for (int i = 0; i < 5; ++i){vec.push_back(i);}// 显示元素for (int i : vec){std::cout << i << std::endl;}return 0;
}

代码解析

  1. AdvancedAllocator:在CustomAllocator基础上,增加了constructdestroy方法,用于元素的构造和析构。
  2. operator==operator!=:定义分配器的比较操作符。
  3. main函数:展示了如何使用高级自定义分配器创建vector容器,并进行元素的添加和显示。

总结

        自定义内存管理技术,如内存池和自定义分配器,在C++中提供了强大的内存管理能力。它们不仅能够提高内存管理的效率,还能满足特定应用场景下的内存管理需求。

  • 内存池(Memory Pool):通过预分配一大块内存并将其划分成多个固定大小的块,实现高效的内存分配和释放。适用于高性能应用和频繁分配和释放相同大小对象的场景。
  • 自定义分配器(Custom Allocators):允许开发者控制容器的内存分配策略,满足特定的性能需求或内存管理策略。适用于高性能应用和特定内存管理需求的场景。

        通过以上示例代码和详细解析,开发者可以更好地理解和应用自定义内存管理技术,从而提高软件质量和开发效率。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • milvus使用milvus migration工具迁移数据
  • Kubernetes 上安装 Jenkins
  • 滑动窗口系列(定长滑动窗口长度)8/31
  • CRMEB商城系统功能解读——渠道码
  • Ant Design vue 多层for循环form表单自定义校验
  • css中的伪类
  • 打卡第58天------图论
  • Stable Diffusion 必备插件推荐,菜鸟轻松成高手!(附插件整合包)
  • 基于爬山法MPPT和PI的直驱式永磁同步风力发电机控制系统simulink建模与仿真
  • string的模拟实现与深浅拷贝
  • 嵌入式全栈开发学习笔记---Linux系统编程(进程间通信)
  • Trying to update a textarea with string from an OpenAI request
  • 使用Python+docx+openpyxl将Word表格转换为Excel表格
  • 如何处理时间序列异常值?理解、检测和替换时间序列中的异常值
  • 掌握Go语言中的Channel:并发编程的核心
  • 【Leetcode】104. 二叉树的最大深度
  • 08.Android之View事件问题
  • 78. Subsets
  • Angular 响应式表单 基础例子
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • CODING 缺陷管理功能正式开始公测
  • ES6 ...操作符
  • es6(二):字符串的扩展
  • HashMap ConcurrentHashMap
  • idea + plantuml 画流程图
  • interface和setter,getter
  • Spring Boot MyBatis配置多种数据库
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • 搞机器学习要哪些技能
  • 构建二叉树进行数值数组的去重及优化
  • 两列自适应布局方案整理
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 数据结构java版之冒泡排序及优化
  • nb
  • 你对linux中grep命令知道多少?
  • const的用法,特别是用在函数前面与后面的区别
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​比特币大跌的 2 个原因
  • ​水经微图Web1.5.0版即将上线
  • # Swust 12th acm 邀请赛# [ K ] 三角形判定 [题解]
  • # 达梦数据库知识点
  • #70结构体案例1(导师,学生,成绩)
  • #git 撤消对文件的更改
  • #Ubuntu(修改root信息)
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • #数学建模# 线性规划问题的Matlab求解
  • (39)STM32——FLASH闪存
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (九)c52学习之旅-定时器
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (算法)Game
  • (推荐)叮当——中文语音对话机器人