0%

C++ 实现内存池

前言

在 C++ 程序中,频繁的内存分配和释放会导致性能下降和内存碎片。内存池(Memory Pool)是一种常用的优化技术,通过预先分配大块内存并管理内存块的分配和回收,可以显著提高程序性能。

内存池原理

内存池的核心思想是:

  • 预先分配一大块内存
  • 将内存划分为固定大小的块
  • 使用空闲链表管理这些内存块
  • 避免频繁调用系统的 malloc/free

实现思路

  1. 内存块结构设计
  2. 空闲链表管理
  3. 内存分配与回收策略
  4. 自动扩容机制

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
class MemoryPool {
private:
struct MemoryBlock {
MemoryBlock* next; // 指向下一个内存块
};

struct MemoryChunk {
MemoryChunk* next; // 指向下一个内存块组
char* memory; // 实际的内存起始位置
};

size_t blockSize; // 每个内存块的大小
size_t chunksPerBlock; // 每组内存块的数量
MemoryBlock* freeList; // 空闲内存块链表
MemoryChunk* chunks; // 内存块组链表

public:
MemoryPool(size_t blockSize = 64, size_t chunksPerBlock = 1024)
: blockSize(std::max(blockSize, sizeof(MemoryBlock)))
, chunksPerBlock(chunksPerBlock)
, freeList(nullptr)
, chunks(nullptr) {
allocateChunk();
}

~MemoryPool() {
// 释放所有内存块组
while (chunks) {
MemoryChunk* next = chunks->next;
delete[] chunks->memory;
delete chunks;
chunks = next;
}
}

void* allocate() {
if (!freeList) {
allocateChunk();
}

MemoryBlock* block = freeList;
freeList = block->next;
return block;
}

void deallocate(void* ptr) {
if (!ptr) return;

// 将释放的内存块添加到空闲链表
MemoryBlock* block = static_cast<MemoryBlock*>(ptr);
block->next = freeList;
freeList = block;
}

private:
void allocateChunk() {
// 分配新的内存块组
MemoryChunk* chunk = new MemoryChunk;
chunk->memory = new char[blockSize * chunksPerBlock];
chunk->next = chunks;
chunks = chunk;

// 初始化空闲链表
char* memory = chunk->memory;
for (size_t i = 0; i < chunksPerBlock - 1; ++i) {
MemoryBlock* block = reinterpret_cast<MemoryBlock*>(memory);
block->next = reinterpret_cast<MemoryBlock*>(memory + blockSize);
memory += blockSize;
}

// 设置最后一个块
MemoryBlock* lastBlock = reinterpret_cast<MemoryBlock*>(memory);
lastBlock->next = freeList;
freeList = reinterpret_cast<MemoryBlock*>(chunk->memory);
}
};

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class MyObject {
int data[16]; // 64字节的对象
public:
MyObject() {
std::fill_n(data, 16, 0);
}
};

int main() {
// 创建内存池,块大小为64字节
MemoryPool pool(sizeof(MyObject));

// 分配对象
MyObject* obj1 = new (pool.allocate()) MyObject();
MyObject* obj2 = new (pool.allocate()) MyObject();

// 释放对象
obj1->~MyObject();
pool.deallocate(obj1);

obj2->~MyObject();
pool.deallocate(obj2);

return 0;
}

性能优化

  1. 内存对齐

    1
    2
    3
    // 确保内存块大小对齐
    blockSize = (blockSize + alignof(std::max_align_t) - 1)
    & ~(alignof(std::max_align_t) - 1);
  2. 线程安全

    1
    2
    std::mutex mutex;
    std::lock_guard<std::mutex> lock(mutex); // 在分配和释放时加锁

优点分析

  1. 性能提升

    • 减少系统调用
    • 降低内存碎片
    • 提高内存分配速度
  2. 内存管理

    • 固定大小分配
    • 快速回收复用
    • 自动扩容
  3. 应用场景

    • 频繁创建销毁的小对象
    • 对象大小固定的场合
    • 高性能服务器程序

注意事项

  1. 内存对齐

    • 考虑平台对齐要求
    • 避免访问未对齐内存
  2. 线程安全

    • 多线程环境下需要加锁
    • 考虑使用无锁算法
  3. 内存泄漏

    • 确保正确释放内存
    • 注意异常安全

总结

内存池是一种重要的性能优化技术,通过合理的内存管理策略,可以显著提升程序性能。本文实现的内存池虽然简单,但包含了核心概念,可以根据实际需求进行扩展和优化。


参考资料:

  1. C++ 高性能编程实践
  2. 《Effective C++》
  3. 《深入理解计算机系统》