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

目录

[1. 内存池(Memory Pool)](#1. 内存池(Memory Pool))

概念

模型

特点

核心点

实现

适用场景

经典示例实现

代码解析

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

概念

模型

特点

核心点

实现

适用场景

经典示例实现

代码解析

高级自定义分配器示例

代码解析

总结


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

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

1. 内存池(Memory Pool)

概念

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

模型

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

特点

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

核心点

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

实现

cpp 复制代码
#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;
    }
};

适用场景

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

经典示例实现

cpp 复制代码
#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方法。
  • 在容器中使用自定义分配器。

实现

cpp 复制代码
#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;
}

适用场景

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

经典示例实现

cpp 复制代码
#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容器,并进行元素的添加和显示。

高级自定义分配器示例

cpp 复制代码
#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):允许开发者控制容器的内存分配策略,满足特定的性能需求或内存管理策略。适用于高性能应用和特定内存管理需求的场景。

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

相关推荐
shinelord明1 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
Monly218 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu9 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee20219 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
小俊俊的博客10 分钟前
海康RGBD相机使用C++和Opencv采集图像记录
c++·opencv·海康·rgbd相机
7yewh12 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
waicsdn_haha23 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
_WndProc25 分钟前
C++ 日志输出
开发语言·c++·算法
薄荷故人_26 分钟前
从零开始的C++之旅——红黑树及其实现
数据结构·c++
m0_7482400227 分钟前
Chromium 中chrome.webRequest扩展接口定义c++
网络·c++·chrome