您的位置:首页 > 文旅 > 美景 > 学懂C++(四十四):C++ 自定义内存管理的深入解析:内存池与自定义分配器

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

2024/10/6 12:19:35 来源:https://blog.csdn.net/martian665/article/details/141561146  浏览:    关键词:学懂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):允许开发者控制容器的内存分配策略,满足特定的性能需求或内存管理策略。适用于高性能应用和特定内存管理需求的场景。

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

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com