因为std::vector/new[]频繁分配小内存会导致堆碎片、锁竞争和元数据开销;固定大小内存池通过预分配+自由链表实现O(1)分配,但要求对象大小严格一致、容量固定、不自动扩容,以性能换灵活性。

为什么不用 std::vector 或 new[] 直接分配?
因为频繁申请释放小块内存(比如每次 64 字节的对象)会导致堆碎片、锁竞争(malloc 多线程下有全局锁)、以及额外的元数据开销。固定大小内存池绕过堆管理器,用预分配大块内存 + 自由链表管理,把 alloc/free 降为 O(1) 指针操作。
关键约束:所有对象大小必须严格一致,且池容量在构造时确定。不支持变长分配,也不自动扩容——这是性能换灵活性的明确取舍。
怎么组织自由链表和内存布局?
最简但高效的方式是把大块内存(char*)划分为等长槽位(slot),每个槽位头部或单独维护一个指向下个空闲槽的指针(即“union free list node”)。推荐把指针直接存在槽位开头,复用对象空间,避免额外数组开销。
- 预分配一块
char* m_pool,大小 =slot_size * capacity - 初始化时遍历所有 slot,将每个 slot 的前
sizeof(void*)字节设为指向下一个空闲 slot 的指针 - 用
void* m_free_list指向第一个空闲 slot;alloc()取头、更新指针;free(ptr)插到头 - 注意对齐:确保
slot_size >= sizeof(void*),且最好按alignof(std::max_align_t)对齐(可用alignas或std::aligned_alloc)
如何避免多线程下的 ABA 和竞争?
单自由链表在并发 alloc/free 下会出错——两个线程同时读到同一 m_free_list,一个 free 后另一个仍用旧值。不能只加互斥锁(会抵消性能优势),应改用无锁结构。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
标准做法是用 std::atomic<void> m_free_list</void> + CAS 循环:
void* alloc() {
void* old = m_free_list.load();
do {
if (!old) return nullptr;
void* next = *static_cast<void**>(old);
} while (!m_free_list.compare_exchange_weak(old, next));
return old;
}注意:CAS 失败后必须重新读 next(因 old 可能已被其他线程修改),且 *static_cast<void>(old)</void> 要求 old 地址可写、对齐正确——这意味着你不能把自由链表指针存在只读内存里,也不能让对象构造函数覆盖它。
析构和重用时最容易漏掉什么?
内存池本身不调用对象的构造/析构函数——它只管字节块。如果你存的是带非平凡析构函数的类型(如 std::string),必须显式调用 obj.~T() 再 free,否则资源泄漏;同理,alloc 返回的内存需用 new (ptr) T{...} 定位构造。
- 提供
alloc_construct()和destroy_free()辅助方法,而非只暴露裸指针 - 池销毁前必须确保所有对象已析构,否则未定义行为
- 不要把池对象放在栈上并存储其地址到长期存活的容器中——池生命周期结束,指针立刻失效
真正难的不是分配逻辑,而是让使用者清楚:这块内存归池管,对象生命周期必须与池协同。漏掉析构或跨生命周期用指针,比内存泄漏更难 debug。


















