内存池
内存池
内存池
内存池(Memory Pool)*是一种*提前分配一大块内存、并在之后反复复用这块内存来分配/释放对象的技术,目的是为了提高性能、降低内存碎片、避免频繁调用 malloc/new
等昂贵操作。
一、为什么要用内存池
标准的 new
/ malloc
调用:
- 都涉及系统调用(如
sbrk
,mmap
),慢; - 易产生碎片;
- 无法保证内存地址的连续性;
- 每次创建/销毁对象都有构造/析构与堆管理开销。
内存池的优势:
优点 | 描述 |
---|---|
快速分配 | 内部通过指针或索引跳转,分配速度远快于 malloc/new |
控制碎片 | 一次性分配大内存块,减少碎片 |
可重用 | 对象销毁后可复用内存,无需反复系统分配 |
可预测性高 | 特别适合实时系统、游戏、数据库、嵌入式等对性能要求极高的场景 |
二、工作原理概览
预分配一块大内存(如
char pool[1024 * 1024]
)把这块内存分成若干个固定大小的块(或管理可变大小)
维护一个空闲链表/栈来跟踪哪些块可用
alloc()
:从空闲列表中拿出一块,构造对象(用placement new
)free()
:调用析构函数,把内存块归还空闲列表
三、简单示例:固定大小内存池
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
// 内存池模板类:管理固定数量(N)对象(类型为 T)的内存复用
template <typename T, size_t N>
class MemoryPool {
private:
// 原始内存块,用于存储 N 个对象的原始字节
// alignas(T) 确保 buffer 对齐到类型 T 的对齐要求,避免未定义行为
alignas(T) char buffer[N * sizeof(T)];
// 空闲列表,保存当前可用的对象地址
std::vector<T*> free_list;
public:
// 构造函数:初始化空闲列表,将 buffer 切分成 N 个对象大小的块
MemoryPool() {
for (size_t i = 0; i < N; ++i) {
// 将 buffer 中每个对象位置转换为 T* 并加入空闲列表
free_list.push_back(reinterpret_cast<T*>(&buffer[i * sizeof(T)]));
}
}
// 分配一个对象
T* allocate() {
// 如果没有可用内存,抛出异常
if (free_list.empty()) throw std::bad_alloc();
// 从空闲列表中取出一个空闲块
T* ptr = free_list.back();
free_list.pop_back();
// 在该内存位置上使用 placement new 构造对象
return new (ptr) T();
}
// 回收一个对象
void deallocate(T* ptr) {
// 显式调用析构函数,释放对象资源
ptr->~T();
// 将内存块重新加入空闲列表,以便后续复用
free_list.push_back(ptr);
}
};
使用示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct MyObject {
int x;
MyObject() { std::cout << "Constructor\n"; }
~MyObject() { std::cout << "Destructor\n"; }
};
int main() {
MemoryPool<MyObject, 10> pool;
MyObject* obj1 = pool.allocate(); // 从池中分配一个对象
pool.deallocate(obj1); // 回收对象
return 0;
}
四、STL 容器也支持内存池
STL 的 allocator 机制允许我们自定义内存分配器:
1
std::vector<int, MyMemoryPoolAllocator<int>> vec;
这让 vector
/map
/set
等容器内部元素也能通过内存池分配,提高性能。
五、注意事项
项目 | 说明 |
---|---|
析构函数需手动调用 | 内存池只分配空间,不会自动析构对象 |
不支持动态大小对象 | 固定块大小的内存池不适合 std::string 、vector 等变长对象 |
线程安全性 | 多线程环境需加锁或使用线程局部内存池 |
内存泄漏风险 | 使用错误容易忘记回收或析构对象 |
本文由作者按照 CC BY 4.0 进行授权