内存池学习笔记(附C++完整实现)

内存池学习笔记(附C++完整实现)

一、内存池核心定义

内存池是程序初始化阶段提前向操作系统申请一块/多块连续的大块内存,按预设规则分割为不同规格的小块内存单元,供程序按需分配、回收与复用 的定制化内存管理机制。其核心目标是减少系统调用开销、降低内存碎片、提升高并发场景下的内存分配效率,是替代C++原生new/delete的高性能方案。

二、原生内存管理的缺点与内存池优势

1. 原生new/delete的核心问题

  • 系统调用开销高 :底层最终调用brk/mmap等系统调用,涉及用户态与内核态的频繁切换,频繁分配/释放小块内存时性能损耗极大;
  • 内存碎片严重 :多次不规则分配释放后,产生外部碎片 (大量零散空闲块总和足够但无法分配连续大块)和内部碎片(分配块大于实际需求导致的空间浪费);
  • 线程安全开销大:标准库分配器的全局锁机制,在多线程高并发场景下会产生严重的锁竞争,导致分配效率骤降;
  • 分配效率不稳定:通用分配器需兼容所有内存大小请求,内部链表管理逻辑复杂,无法针对特定场景优化。

2. 内存池的核心优势

优势 具体说明
降低系统调用次数 一次性向OS申请大块内存,后续分配/回收均在用户态完成,无内核态切换开销
减少内存碎片 按固定规格分割内存块,按需匹配请求大小,避免零散空闲块产生;分级管理进一步降低内部碎片
提升分配效率 预设内存块结构,分配时直接从空闲链表取块,回收时快速挂回,逻辑简单且高效
内存复用性强 释放的内存块不立即归还给OS,而是加入空闲链表供后续复用,避免重复申请释放
定制化适配性 可针对业务场景定制内存块规格、池大小,适配高并发、嵌入式等特殊场景

三、内存池核心设计思路

1. 设计三要素

  1. 预分配:程序启动/初始化时,主动向操作系统申请连续的大块内存,作为内存池的基础缓冲区;
  2. 分块管理 :将大块缓冲区划分为固定大小的内存块(槽Slot) ,通过原子空闲链表管理所有空闲块,支持快速取块和挂块;
  3. 按需分配与回收:分配时根据请求大小匹配最合适的内存块,从空闲链表取出;回收时将内存块重新挂回空闲链表,标记为可用状态。

2. 经典内存池类型

内存池类型 核心特点 适用场景 本示例实现类型
定长内存池 所有内存块大小完全相同,管理逻辑最简单,效率最高 频繁分配相同大小对象的场景(如链表节点、网络数据包、固定结构对象) 子池基础(64个定长子池)
分级内存池 划分多个定长子池,每个子池对应一种固定规格的内存块,按需匹配请求 内存请求大小不固定的通用场景(如业务开发、高并发服务) 整体架构(HashBucket分级)
动态扩容内存池 初始分配固定大小内存,空闲块耗尽时自动向OS申请新块,扩展池容量 内存使用量波动较大的场景 本示例核心特性

3. 本示例核心设计架构

本示例采用HashBucket分级内存池架构核心设计如下:

  1. 分级子池:共64个定长内存池子池,槽大小从8B开始,以8B为步长递增(8B、16B、24B...512B),覆盖大部分小内存请求;
  2. Hash映射:根据内存请求大小,通过哈希计算快速匹配对应的子池(如申请20B内存,映射到24B的子池);
  3. 大内存兜底 :超过512B的内存请求,直接使用C++原生operator new/operator delete,避免大内存块造成的内部碎片;
  4. 双空闲管理 :未被使用过的新槽通过指针偏移管理,已释放的旧槽通过原子空闲链表管理,优先复用旧槽;
  5. 无锁+细粒度锁 :空闲链表操作采用CAS无锁机制 ,内存块扩容采用细粒度互斥锁,兼顾效率与线程安全;
  6. 内存对齐:所有内存槽均按自身大小对齐,避免未对齐导致的性能损耗或硬件错误;
  7. 对象构造/析构分离 :通过定位new在分配的内存上构造对象,析构时先调用析构函数再回收内存,符合C++对象生命周期管理。

四、C++完整实现

1. 头文件(MemoryPool.h)

cpp 复制代码
#pragma once 

#include <atomic>
#include <cassert>
#include <cstdint>
#include <mutex>

namespace MemoryPool
{
	const int MEMORY_POOL_NUM = 64;    // 分级内存池数量:64个定长子池
	const int SLOT_BASE_SIZE = 8;      // 槽基础大小:8字节,步长8字节
	const int MAX_SLOT_SIZE = 512;     // 最大槽大小:512字节,超过则用原生new/delete

/**
 * 内存槽结构体:用于管理空闲链表和内存块
 * 注意:sizeof(Slot) 并非实际槽大小,实际槽大小由对应MemoryPool的slotSize_指定
 * 原子指针保证多线程下next指针操作的原子性,支持无锁CAS
 */
struct Slot 
{
    std::atomic<Slot*> next; // 原子指针:指向空闲链表下一个槽,无锁操作核心
};

/**
 * 定长内存池子类:单个定长子池,管理一种固定大小的内存槽
 * 核心特性:动态扩容、无锁空闲链表、内存对齐、细粒度锁扩容
 */
class MemoryPool
{
public:
    // 构造函数:指定内存块大小(默认4096字节,页大小对齐)
    explicit MemoryPool(size_t blockSize = 4096);
    // 析构函数:释放所有向OS申请的内存块
    ~MemoryPool();
    
    // 初始化:设置当前子池的槽大小,重置所有状态
    void init(size_t slotSize);
    // 分配内存:返回一个可用的内存槽指针
    void* allocate();
    // 回收内存:将释放的指针挂回空闲链表
    void deallocate(void* ptr);

private:
    // 扩容:向OS申请新的内存块,加入当前池并分割为槽
    void allocateNewBlock();
    // 内存对齐:计算指定指针到目标对齐数的填充大小
    size_t padPointer(char* p, size_t align);

    // 无锁入队:将槽推入空闲链表头部,CAS操作保证原子性
    bool pushFreeList(Slot* slot);
    // 无锁出队:从空闲链表头部取出一个槽,CAS操作保证原子性
    Slot* popFreeList();

private:
    size_t             blockSize_;  // 单个内存块大小(向OS申请的大块内存大小)
    size_t             slotSize_;   // 当前池的内存槽大小(固定值,8的倍数)
    Slot*              firstBlock_; // 指向当前池管理的首个内存块(块链表头)
    Slot*              curSlot_;    // 指向当前内存块中未被使用过的新槽
    std::atomic<Slot*> freeList_;   // 原子空闲链表头:管理已释放的可复用槽(无锁核心)
    Slot*              lastSlot_;   // 当前内存块的最后一个有效槽标记:超过则需扩容
    std::mutex         mutexForBlock_; // 细粒度互斥锁:保证扩容操作的线程安全,避免重复申请内存块
};

/**
 * 哈希桶分级内存池:对外提供统一接口,管理64个定长MemoryPool子池
 * 单例模式:子池数组为静态局部变量,保证全局唯一且懒加载
 * 核心功能:内存大小映射、子池获取、分配/回收封装、对象构造/析构
 */
class HashBucket
{
public:
    // 初始化所有子池:设置每个子池的槽大小(8B~512B,步长8B)
    static void initMemoryPool();
    // 获取指定索引的子池:单例模式,返回静态子池数组的引用
    static MemoryPool& getMemoryPool(int index);

    /**
     * 对外内存分配接口:根据大小自动匹配子池或使用原生new
     * @param size 申请的内存大小
     * @return 分配的内存指针,失败返回nullptr
     */
    static void* useMemory(size_t size)
    {
        if (size <= 0) return nullptr;
        // 大内存兜底:超过512B直接使用原生operator new
        if (size > MAX_SLOT_SIZE) return operator new(size);
        // 哈希映射:size/8向上取整,计算对应的子池索引((size+7)/8 -1)
        int poolIndex = ((size + SLOT_BASE_SIZE - 1) / SLOT_BASE_SIZE) - 1;
        return getMemoryPool(poolIndex).allocate();
    }

    /**
     * 对外内存回收接口:根据大小自动匹配子池或使用原生delete
     * @param ptr 待释放的内存指针
     * @param size 内存块的实际大小(需与分配时一致)
     */
    static void freeMemory(void* ptr, size_t size)
    {
        if (!ptr) return;
        // 大内存兜底:超过512B直接使用原生operator delete
        if (size > MAX_SLOT_SIZE)
        {
            operator delete(ptr);
            return;
        }
        // 哈希映射:找到对应的子池进行回收
        int poolIndex = ((size + SLOT_BASE_SIZE - 1) / SLOT_BASE_SIZE) - 1;
        getMemoryPool(poolIndex).deallocate(ptr);
    }

    // 友元模板函数:对象构造与析构,封装定位new和析构函数调用
    template<typename T, typename... Args> 
    friend T* newElement(Args&&... args);
    
    template<typename T>
    friend void deleteElement(T* p);
};

/**
 * 模板函数:创建对象(内存分配+定位构造)
 * 完美转发参数,支持任意构造函数,符合C++11及以上特性
 * @param args 构造函数的参数包
 * @return 构造完成的对象指针,内存分配失败返回nullptr
 */
template<typename T, typename... Args>
T* newElement(Args&&... args)
{
    T* p = reinterpret_cast<T*>(HashBucket::useMemory(sizeof(T)));
    if (p != nullptr)
    {
        // 定位new:在已分配的内存上构造对象,不重新申请内存
        new(p) T(std::forward<Args>(args)...);
    }
    return p;
}

/**
 * 模板函数:销毁对象(析构+内存回收)
 * 先调用对象的析构函数,再回收内存,严格遵循C++对象生命周期
 * @param p 待销毁的对象指针
 */
template<typename T>
void deleteElement(T* p)
{
    if (p != nullptr)
    {
        // 显式调用析构函数:释放对象内部资源
        p->~T();
        // 回收内存:调用哈希桶的回收接口
        HashBucket::freeMemory(reinterpret_cast<void*>(p), sizeof(T));
    }
}

} // namespace MemoryPool

2. 源文件(MemoryPool.cpp)- 核心逻辑实现

cpp 复制代码
#include "MemoryPool.h"

namespace KamaMemoryPool 
{
// MemoryPool构造函数:初始化所有成员变量,设置默认块大小
MemoryPool::MemoryPool(size_t blockSize)
    : blockSize_(blockSize)
    , slotSize_(0)
    , firstBlock_(nullptr)
    , curSlot_(nullptr)
    , freeList_(nullptr)
    , lastSlot_(nullptr)
{}

// MemoryPool析构函数:释放所有向OS申请的内存块(块链表遍历)
MemoryPool::~MemoryPool()
{
    Slot* curBlock = firstBlock_;
    while (curBlock != nullptr)
    {
        // 保存下一个块的指针,避免释放后悬空
        Slot* nextBlock = curBlock->next.load(std::memory_order_relaxed);
        // 原生operator delete:释放向OS申请的连续大块内存,无需调用析构
        operator delete(reinterpret_cast<void*>(curBlock));
        curBlock = nextBlock;
    }
}

// 初始化子池:设置槽大小,重置所有状态为初始值
void MemoryPool::init(size_t slotSize)
{
    assert(slotSize > 0 && "Slot size must be greater than 0");
    slotSize_ = slotSize;
    firstBlock_ = nullptr;
    curSlot_ = nullptr;
    freeList_.store(nullptr, std::memory_order_relaxed);
    lastSlot_ = nullptr;
}

/**
 * 内存分配核心逻辑:优先复用空闲链表的旧槽,再使用新槽,无槽则扩容
 * 无锁操作空闲链表,细粒度锁保护扩容,兼顾效率与线程安全
 * @return 可用的内存槽指针,永不返回nullptr(扩容保证)
 */
void* MemoryPool::allocate()
{
    // 第一步:优先从无锁空闲链表取块,复用已释放的内存(无锁,效率最高)
    Slot* slot = popFreeList();
    if (slot != nullptr)
    {
        return slot;
    }

    // 第二步:无空闲旧槽,使用当前块的新槽,扩容操作加细粒度锁
    Slot* tempSlot = nullptr;
    {
        // 加锁:仅保护扩容和curSlot_/lastSlot_操作,锁粒度极小
        std::lock_guard<std::mutex> lock(mutexForBlock_);
        // 检查当前块是否还有新槽,无则申请新块(扩容)
        if (curSlot_ >= lastSlot_)
        {
            allocateNewBlock();
        }
        // 取出当前新槽,并将curSlot_后移(指向下一个新槽)
        tempSlot = curSlot_;
        // 指针偏移:Slot*类型,需按slotSize_计算偏移步长(slotSize_ / sizeof(Slot))
        curSlot_ += slotSize_ / sizeof(Slot);
    }

    return tempSlot;
}

// 内存回收核心逻辑:将释放的指针转为Slot,挂回无锁空闲链表
void MemoryPool::deallocate(void* ptr)
{
    if (ptr == nullptr) return;
    // 类型转换:将void*转为Slot*,加入空闲链表
    Slot* slot = reinterpret_cast<Slot*>(ptr);
    pushFreeList(slot);
}

/**
 * 扩容核心逻辑:向OS申请新块,加入块链表,分割为槽并做内存对齐
 * 仅在当前块无新槽时调用,且被mutexForBlock_保护,线程安全
 */
void MemoryPool::allocateNewBlock()
{
    // 向OS申请大块内存:大小为blockSize_,返回void*
    void* newBlock = operator new(blockSize_);
    Slot* newBlockSlot = reinterpret_cast<Slot*>(newBlock);
    // 块链表头插法:将新块加入块链表,方便后续析构遍历
    newBlockSlot->next.store(firstBlock_, std::memory_order_relaxed);
    firstBlock_ = newBlockSlot;

    // 计算内存块体起始地址:跳过块链表的next指针(sizeof(Slot*))
    char* blockBody = reinterpret_cast<char*>(newBlock) + sizeof(Slot*);
    // 内存对齐:计算块体起始地址到slotSize_对齐的填充大小
    size_t paddingSize = padPointer(blockBody, slotSize_);
    // 设置当前新槽起始地址:对齐后的块体地址
    curSlot_ = reinterpret_cast<Slot*>(blockBody + paddingSize);
    // 设置当前块最后一个有效槽标记:避免越界,预留slotSize_大小
    lastSlot_ = reinterpret_cast<Slot*>(
        reinterpret_cast<size_t>(newBlock) + blockSize_ - slotSize_ + 1
    );
}

/**
 * 内存对齐计算:计算指定指针到目标对齐数的填充大小
 * @param p 待对齐的指针
 * @param align 对齐数(当前池的slotSize_)
 * @return 需填充的字节数,0表示已对齐
 */
size_t MemoryPool::padPointer(char* p, size_t align)
{
    // 计算指针地址对对齐数的余数
    size_t remainder = reinterpret_cast<size_t>(p) % align;
    // 余数为0则已对齐,否则填充(align - remainder)字节
    return (remainder == 0) ? 0 : (align - remainder);
}

/**
 * 无锁入队:CAS操作将槽推入空闲链表头部
 * 循环CAS直到成功,保证多线程下的原子性,无锁竞争
 * @param slot 待入队的空闲槽
 * @return 入队成功返回true(恒返回true,循环保证)
 */
bool MemoryPool::pushFreeList(Slot* slot)
{
    while (true)
    {
        // 加载当前空闲链表头:宽松内存序,仅获取值
        Slot* oldHead = freeList_.load(std::memory_order_relaxed);
        // 设置新槽的next为当前头:准备头插
        slot->next.store(oldHead, std::memory_order_relaxed);
        // CAS原子操作:将freeList_从oldHead更新为slot
        // 成功:返回true;失败:说明其他线程修改了freeList_,重试
        if (freeList_.compare_exchange_weak(
            oldHead, slot,
            std::memory_order_release,  // 成功:释放内存序,保证写操作可见性
            std::memory_order_relaxed   // 失败:宽松内存序,减少开销
        ))
        {
            return true;
        }
    }
}

/**
 * 无锁出队:CAS操作从空闲链表头部取出一个槽
 * 循环CAS直到成功或队列为空,保证多线程下的原子性
 * @return 取出的空闲槽,队列为空返回nullptr
 */
Slot* MemoryPool::popFreeList()
{
    while (true)
    {
        // 加载当前空闲链表头:获取内存序,保证读操作可见性
        Slot* oldHead = freeList_.load(std::memory_order_acquire);
        // 队列为空,直接返回nullptr
        if (oldHead == nullptr)
        {
            return nullptr;
        }

        // 加载旧头的下一个节点:准备更新链表头
        Slot* newHead = oldHead->next.load(std::memory_order_relaxed);
        // CAS原子操作:将freeList_从oldHead更新为newHead
        // 成功:返回oldHead(取出的槽);失败:重试
        if (freeList_.compare_exchange_weak(
            oldHead, newHead,
            std::memory_order_acquire,  // 成功:获取内存序
            std::memory_order_relaxed   // 失败:宽松内存序
        ))
        {
            return oldHead;
        }
    }
}

// 初始化所有子池:遍历64个子池,设置每个子池的槽大小(8B*(i+1))
void HashBucket::initMemoryPool()
{
    for (int i = 0; i < MEMORY_POOL_NUM; ++i)
    {
        getMemoryPool(i).init(static_cast<size_t>((i + 1) * SLOT_BASE_SIZE));
    }
}

/**
 * 获取子池:单例模式,静态局部数组保证全局唯一且懒加载
 * @param index 子池索引(0~63)
 * @return 对应子池的引用,避免拷贝,保证全局唯一
 */
MemoryPool& HashBucket::getMemoryPool(int index)
{
    assert(index >= 0 && index < MEMORY_POOL_NUM && "Pool index out of range");
    // 静态局部数组:程序运行期仅初始化一次,单例且线程安全(C++11及以上)
    static MemoryPool memoryPool[MEMORY_POOL_NUM];
    return memoryPool[index];
}

} // namespace KamaMemoryPool

3. 测试示例(main.cpp)- 验证使用方式

cpp 复制代码
#include "MemoryPool.h"
#include <iostream>
#include <string>
#include <thread>
#include <vector>

using namespace KamaMemoryPool;

// 测试自定义类
class TestObject
{
private:
    int a;
    std::string b;
public:
    TestObject(int a_, std::string b_) : a(a_), b(b_)
    {
        std::cout << "TestObject构造:a=" << a << ", b=" << b << std::endl;
    }

    ~TestObject()
    {
        std::cout << "TestObject析构:a=" << a << ", b=" << b << std::endl;
    }

    void show()
    {
        std::cout << "TestObject:a=" << a << ", b=" << b << std::endl;
    }
};

// 多线程测试函数:分配并释放大量对象,验证线程安全
void multiThreadTest(int threadId, int count)
{
    std::vector<TestObject*> objs;
    objs.reserve(count);

    // 分配count个对象
    for (int i = 0; i < count; ++i)
    {
        objs.push_back(newElement<TestObject>(threadId * 1000 + i, "test_" + std::to_string(threadId)));
    }

    // 访问对象
    for (auto p : objs)
    {
        p->show();
    }

    // 释放对象
    for (auto p : objs)
    {
        deleteElement(p);
    }

    std::cout << "线程" << threadId << ":完成" << count << "个对象的分配与释放" << std::endl;
}

int main()
{
    // 第一步:初始化内存池(必须先调用,建议程序启动时调用)
    HashBucket::initMemoryPool();
    std::cout << "内存池初始化完成" << std::endl;

    // 单线程测试
    std::cout << "\n===== 单线程测试 =====" << std::endl;
    TestObject* p1 = newElement<TestObject>(100, "single_thread");
    if (p1)
    {
        p1->show();
        deleteElement(p1);
    }

    // 多线程测试:4个线程,每个线程分配100个对象
    std::cout << "\n===== 多线程测试 =====" << std::endl;
    std::vector<std::thread> threads;
    for (int i = 0; i < 4; ++i)
    {
        threads.emplace_back(multiThreadTest, i, 100);
    }

    // 等待所有线程完成
    for (auto& t : threads)
    {
        t.join();
    }

    std::cout << "\n所有测试完成,内存池自动析构释放所有内存" << std::endl;
    return 0;
}

五、核心实现细节与优化点解析

1. 无锁CAS操作(线程安全核心优化)

  • 核心对象std::atomic<Slot*> freeList_(原子空闲链表头)、Slot::next(原子链表节点);
  • 核心操作pushFreeList(CAS头插入队)、popFreeList(CAS头删除队);
  • 优势:替代全局互斥锁,多线程操作空闲链表时无锁竞争,大幅提升高并发场景下的效率;
  • 内存序优化 :使用std::memory_order_relaxed(宽松)、std::memory_order_acquire(获取)、std::memory_order_release(释放),在保证内存可见性的前提下,减少内存屏障开销,提升性能。

2. 细粒度锁设计(扩容线程安全优化)

  • 锁的作用范围 :仅保护allocateNewBlock(扩容)和curSlot_/lastSlot_的指针偏移操作;
  • 锁的粒度:极小,仅在当前块无新槽时才会加锁,且加锁后操作逻辑简单,耗时极短;
  • 锁的类型std::lock_guard(RAII机制,自动加锁解锁,避免死锁);
  • 优势:避免全局大锁的严重竞争,兼顾扩容操作的线程安全和分配效率。

3. 双空闲管理机制(内存复用优化)

  • 已释放槽 :通过freeList_(原子空闲链表)管理,优先复用,减少内存碎片;
  • 新槽 :通过curSlot_/lastSlot_指针偏移管理,未被使用过,无需链表操作,效率更高;
  • 分配优先级:先复用已释放槽,再使用新槽,最后扩容,最大化内存复用率,减少内存浪费。

4. 内存对齐处理(性能与兼容性优化)

  • 对齐函数padPointer,保证内存槽的起始地址为slotSize_的整数倍;
  • 对齐必要性:硬件对对齐内存的访问速度更快,避免未对齐导致的性能损耗;部分硬件不支持未对齐访问,会直接触发错误;
  • 对齐范围:新申请的内存块体均做对齐处理,所有分配的内存槽均满足对齐要求。

5. 分级哈希映射(通用场景适配优化)

  • 分级设计:64个定长子池,覆盖8B~512B的内存请求,满足大部分小内存场景;
  • 哈希计算(size + 7) / 8 - 1,实现size/8的向上取整,快速匹配最小的可用子池,减少内部碎片;
  • 大内存兜底 :超过512B的请求直接使用原生new/delete,避免大内存块造成的严重内部碎片,兼顾通用性和效率。

6. 对象生命周期管理(C++特性适配)

  • 定位newnew(p) T(std::forward<Args>(args)...),在已分配的内存上构造对象,实现内存分配对象构造分离;
  • 显式析构p->~T(),在回收内存前显式调用析构函数,释放对象内部资源(如std::string的堆内存),避免内存泄漏;
  • 完美转发std::forward<Args>(args)...,支持任意构造函数参数,包括左值、右值,符合C++11及以上的现代特性;
  • 模板封装newElement/deleteElement模板函数,对外提供简洁的对象创建/销毁接口,屏蔽底层内存管理细节。

7. 动态扩容与块链表管理(内存利用率优化)

  • 动态扩容:仅在当前块无新槽时才向OS申请新块,避免初始申请过大内存造成的资源浪费;
  • 块链表:采用头插法管理所有向OS申请的内存块,析构时遍历链表即可释放所有内存,避免内存泄漏;
  • 内存复用:释放的内存块不立即归还给OS,而是加入空闲链表供后续复用,减少系统调用次数。

六、技术点总结表

技术点 核心作用 本示例实现方式
分级内存池 适配通用内存请求,减少内部碎片 HashBucket管理64个定长子池,8B~512B步长8B
无锁CAS操作 实现空闲链表的原子操作,提升高并发效率 std::atomic+compare_exchange_weak,push/pop无锁
细粒度锁 保证扩容线程安全,减少锁竞争 std::lock_guard保护allocateNewBlock,锁粒度极小
内存对齐 提升内存访问速度,保证硬件兼容性 padPointer函数计算填充大小,槽地址按slotSize_对齐
定位new 实现内存分配与对象构造分离 new§ T(...)在已分配内存上构造对象
显式析构 释放对象内部资源,避免内存泄漏 回收内存前调用p->~T(),显式析构对象
哈希映射 快速匹配内存请求与子池,提升分配效率 (size+7)/8-1实现size/8向上取整,映射子池索引
双空闲管理 最大化内存复用,提升分配效率 空闲链表管理已释放槽,指针偏移管理新槽,优先复用旧槽
动态扩容 提高内存利用率,避免初始资源浪费 无新槽时调用allocateNewBlock向OS申请新块,头插法加入块链表
大内存兜底 兼顾通用性,避免大内存内部碎片 超过512B直接使用operator new/operator delete
RAII机制 保证锁的自动释放,避免死锁 std::lock_guard管理互斥锁,作用域结束自动解锁
完美转发 支持任意构造函数参数,适配现代C++ std::forward转发参数包,兼容左值/右值参数
单例模式 保证子池全局唯一,避免重复创建 静态局部MemoryPool数组,getMemoryPool返回引用
块链表管理 统一管理所有OS申请的内存,避免泄漏 头插法构建块链表,析构时遍历释放所有块

七、与经典内存池实现的对比

实现方案 核心特点 优势 劣势 本示例定位
基础定长内存池 单一定长块,管理逻辑简单 实现容易,效率极高 适用场景单一,有内部碎片 本示例的子池基础
本示例分级内存池 64个定长子池,无锁+细粒度锁 通用场景适配,高并发高效,线程安全 实现较复杂,有少量内部碎片 工业级基础版本
tcmalloc(Google) 多级缓存+TLS+页管理 极致高并发,低锁竞争,内存利用率高 实现极其复杂,体积较大 本示例的升级方向
jemalloc(FreeBSD) 分级池+多核优化+页分配 多核性能优异,碎片率低 配置复杂,适合服务端 高并发服务端适配参考
嵌入式静态内存池 无动态扩容,固定大小 资源占用可控,无内存溢出风险 灵活性差,需提前预估内存使用 嵌入式场景适配方向

总结

内存池是一种预分配内存并进行重复利用的技术,通过减少频繁的动态内存分配与释放操作,从而提高程序运行效率。内存池通常预先分配一块大的内存区域,将其划分为多个小块,每次需要分配内存时直接从这块区域中分配,而不是调用系统的动态分配函数(如new或malloc)。简单来说就是申请一块较大的内存块(不够继续申请),之后将这块内存的管理放在应用层执行,减少系统调用带来的开销。

相关推荐
Rousson2 小时前
硬件学习笔记--94 小型光伏板原理、结构、功率及电流计算介绍
学习
嵌入式×边缘AI:打怪升级日志2 小时前
USBX虚拟串口源码分析与改造笔记
笔记·学习笔记·usb
Trouvaille ~2 小时前
【Linux】线程概念与控制(一):线程本质与虚拟地址空间
linux·运维·服务器·c++·线程·虚拟地址空间·pcb
难得的我们2 小时前
C++中的状态模式
开发语言·c++·算法
xhbaitxl2 小时前
算法学习day27-贪心算法
学习·算法·贪心算法
啊阿狸不会拉杆2 小时前
《计算机操作系统》第十章 - 多处理机操作系统
c++·算法·计算机组成原理·os·计算机操作系统
Sarvartha2 小时前
RAG学习笔记
人工智能·学习·飞书
BlackWolfSky2 小时前
鸿蒙中级课程笔记3—ArkUI进阶6—ArkUI性能优化实践(长列表加载性能优化)
笔记·华为·harmonyos
马猴烧酒.2 小时前
智能协图云图库学习笔记day6-主流图片优化技术
笔记·学习