c++固定大小内存池通过预分配连续内存块并用自由链表管理空闲块,实现O(1)分配/释放;需注意对齐、链表初始化及线程安全。

用C++实现一个简单的内存池,核心是预先分配一大块连续内存,避免频繁调用new/delete或malloc/free带来的系统开销和碎片问题。它适合对象大小固定、生命周期短且高频创建/销毁的场景(比如游戏中的粒子、网络包缓冲区)。
设计一个固定大小的内存池
最实用的入门方案是“单块固定尺寸”内存池:所有分配的内存块大小一致,管理简单、无碎片、速度极快。
- 启动时一次性申请一大块原始内存(如
std::vector或new char[n]) - 用自由链表(free list)管理空闲块:每个空闲块头部存下一个空闲块的地址(即指针)
- 分配时取链表头,更新头指针;释放时把块地址插回链表头——都是O(1)操作
- 注意对齐:确保每块起始地址满足
alignof(std::max_align_t)或目标类型的对齐要求(可用std::align辅助)
关键代码结构示例
以下是一个轻量、无依赖的模板实现片段(省略异常处理和线程安全):
template class SimpleMemoryPool { alignas(BlockSize) char buffer[BlockSize * BlockCount]; std::byte* free_list = nullptr; public: SimpleMemoryPool() { // 构建初始空闲链表:每个块头存下一个块地址 for (size_t i = 0; i < BlockCount - 1; ++i) { auto block = buffer + i BlockSize; *reinterpret_cast>(block) = block + BlockSize; } free_list = buffer; reinterpret_cast>(buffer + (BlockCount - 1) BlockSize) = nullptr; }
void* allocate() { if (!free_list) return nullptr; void* ptr = free_list; free_list = *reinterpret_cast(free_list); return ptr; } void deallocate(void* ptr) { if (!ptr) return; *reinterpret_cast(ptr) = free_list; free_list = static_cast(ptr); }
};
立即学习“C++免费学习笔记(深入)”;
使用时:SimpleMemoryPool pool; → 分配64字节块,最多1024个。
配合自定义operator new和delete
让类直接使用该池,可重载其成员函数:
struct Particle { float x, y, life; static SimpleMemoryPool pool; void* operator new(size_t) { return pool.allocate(); } void operator delete(void* p) { pool.deallocate(p); }
};
立即学习“C++免费学习笔记(深入)”;
这样new Particle就走池子,delete p也自动归还,对业务代码透明。
注意事项与进阶方向
这个简单池不处理多线程竞争,也不支持变长分配。实际项目中需考虑:
- 加锁(如
std::mutex)或用无锁链表(atomic操作)支持并发 - 多个池按不同尺寸分级(如8/16/32/64/128字节),降低内部碎片
- 定期统计使用率,避免长期占用不释放(尤其在长生命周期服务中)
- 调试时可加入标记位、边界检查、释放后写毒值(poisoning)辅助排查use-after-free
不复杂但容易忽略对齐和链表初始化细节,写完建议用ASan或Valgrind验证内存行为。