在高性能系统或者嵌入式开发中,频繁的 new/delete 会产生大量的堆碎片和系统调用,导致内存分配成为瓶颈。通过实现一个自定义内存池(Memory Pool),可以将大块内存按需划分,显著提升分配速度并降低碎片。下面给出一个简单而实用的内存池实现思路,并附上完整的示例代码。
1. 设计思路
- 预分配大块
在构造函数中一次性从系统堆中申请一大块内存(比如 1 MiB)。 - 链表管理
将这块内存划分成若干固定大小的块(Block),并用单向链表链接未使用的块。 - 分配/释放
allocate():返回链表头节点,并把链表头指向下一个可用块。deallocate(ptr):将ptr重新插入链表头。
- 扩容
当链表为空时(无可用块),可以再次申请一块新的大块,继续扩展池。 - 线程安全
为了演示,使用std::mutex保护分配/释放操作;如果需要更高并发,可考虑无锁实现或 per‑thread 子池。
2. 关键参数
- BLOCK_SIZE:单个对象的大小(包括对齐)。
- POOL_SIZE:每次申请的大块大小,建议为
BLOCK_SIZE * NUM_BLOCKS_PER_POOL。 - NUM_BLOCKS_PER_POOL:每块大内存中可分配的块数。
3. 示例代码
#include <cstddef>
#include <cstdlib>
#include <mutex>
#include <iostream>
#include <vector>
#include <cassert>
class SimpleMemoryPool
{
public:
explicit SimpleMemoryPool(std::size_t blockSize = 64,
std::size_t blocksPerPool = 1024)
: blockSize_(blockSize)
, blocksPerPool_(blocksPerPool)
, freeList_(nullptr)
{
// 预分配第一个池
allocatePool();
}
~SimpleMemoryPool()
{
for (auto pool : pools_)
std::free(pool);
}
// 禁止拷贝
SimpleMemoryPool(const SimpleMemoryPool&) = delete;
SimpleMemoryPool& operator=(const SimpleMemoryPool&) = delete;
void* allocate()
{
std::lock_guard<std::mutex> lock(mutex_);
if (!freeList_)
allocatePool(); // 再无空闲块时扩容
void* ptr = freeList_;
freeList_ = reinterpret_cast<Block*>(freeList_->next);
return ptr;
}
void deallocate(void* ptr)
{
std::lock_guard<std::mutex> lock(mutex_);
auto block = reinterpret_cast<Block*>(ptr);
block->next = freeList_;
freeList_ = block;
}
private:
struct Block
{
Block* next;
};
void allocatePool()
{
std::size_t poolSize = blockSize_ * blocksPerPool_;
void* pool = std::malloc(poolSize);
if (!pool)
throw std::bad_alloc();
pools_.push_back(pool);
// 将新池划分成块,并插入链表
char* p = static_cast<char*>(pool);
for (std::size_t i = 0; i < blocksPerPool_; ++i)
{
auto block = reinterpret_cast<Block*>(p + i * blockSize_);
block->next = freeList_;
freeList_ = block;
}
}
const std::size_t blockSize_;
const std::size_t blocksPerPool_;
std::vector<void*> pools_;
Block* freeList_;
std::mutex mutex_;
};
// 测试
struct TestStruct
{
int a[4];
double b;
};
int main()
{
SimpleMemoryPool pool(sizeof(TestStruct));
// 分配 10 个 TestStruct
std::vector<void*> ptrs;
for (int i = 0; i < 10; ++i)
{
void* p = pool.allocate();
ptrs.push_back(p);
// 在内存中构造对象
new (p) TestStruct{ {i, i+1, i+2, i+3}, 3.14 };
}
// 使用后析构并归还
for (void* p : ptrs)
{
static_cast<TestStruct*>(p)->~TestStruct();
pool.deallocate(p);
}
std::cout << "Memory pool demo finished.\n";
return 0;
}
代码要点
- 对齐:默认
malloc具备足够的对齐,若需要特殊对齐可使用std::aligned_alloc。 - 构造/析构:
allocate()只返回裸内存,若需要对象构造,请使用placement new;deallocate()只处理内存回收,析构需要自己调用。 - 性能:分配/释放时仅需一次指针操作和一次锁操作,远快于系统堆。
- 可扩展:可以在
allocatePool()里加入自适应策略(例如按需扩大blocksPerPool_)。
4. 小结
自定义内存池是提升 C++ 程序性能的一大利器。通过上述实现,你可以快速集成一个基础池,并根据需求进一步优化(如对象复用、线程局部池、分块大小动态调整等)。在对实时性或内存碎片有严苛要求的项目中,使用内存池往往能带来显著收益。