轻量内存池通过预分配连续内存并用自由链表管理固定大小对象,避免系统调用与碎片;支持多尺寸分组(slab)、线程局部池+无锁中央池、RAII集成及STL兼容分配器。

用C++实现一个轻量、可控的内存池,核心是预先分配一大块内存,避免频繁调用 new/delete 或 malloc/free,从而减少系统调用开销和内存碎片。它不追求通用性,而是针对固定大小对象(如节点、消息包)做极致优化。
基础单块固定大小内存池(最简可用版)
适用于对象大小统一、生命周期集中管理的场景(比如链表节点、事件结构体)。关键思路:用数组模拟空闲链表,通过指针而非下标管理可用块。
- 在构造时一次性
malloc一块连续内存,按对象大小切分成若干“槽位” - 维护一个指向首个空闲槽的指针(即自由链表头),每次
alloc()取头、更新指针;free(ptr)将 ptr 插回链表头 - 所有内存布局完全在用户空间,无额外元数据开销(不存 size、flag 等)
- 示例:若对象为
struct Node { int val; Node* next; };,大小为 16 字节(对齐后),可切分 1024 个槽位 → 总内存约 16KB
支持多尺寸的内存池(slab + size-class 分组)
真实项目中对象大小往往不唯一。可借鉴 Linux slab 分配器思想:按常用尺寸(如 16B/32B/64B/128B/256B/512B/1K/2K/4K)预设若干“池子”,每个池只管一种 size。
- 定义 size class 表(静态数组),每个元素对应一个
MemoryPool实例(T 是该档位代表类型,或用 void* + offset 模拟) - 分配时按请求字节数向上取整到最近的 class(可用查表或 bit-scan 指令加速),命中即走对应池
- 每个子池内部仍用单块+自由链表,但支持批量预分配(如一次 malloc 1MB,拆成 64 个 16KB slab)提升局部性
- 注意:小尺寸池容易内部碎片,大尺寸池接近 malloc,需根据 profile 数据调整 class 划分粒度
线程安全与无锁设计(高并发关键)
多线程争抢同一内存池会成为瓶颈。推荐每线程私有池(thread-local pool)+ 中央后备池(central fallback)组合策略。
iHuzuCMS狐族内容管理系统,是国内CMS市场的新秀、也是国内少有的采用微软的ASP.NET 2.0 + SQL2000/2005 技术框架开发的CMS,充分利用ASP.NET架构的优势,突破传统ASP类CMS的局限性,采用更稳定执行速度更高效的面向对象语言C#设计,全新的模板引擎机制, 全新的静态生成方案,这些功能和技术上的革新塑造了一个基础结构稳定功能创新和执行高效的CMS。iHuzu E
立即学习“C++免费学习笔记(深入)”;
- 主线程或每个 worker 线程拥有自己的
thread_local static Pool,99% 分配直接走本地,零同步tlp; - 本地池耗尽时,向中央池申请一批新块(如 128 个 Node),填满本地自由链表;归还时也先填本地,溢出再交还中央
- 中央池本身可用原子操作 + 无锁栈(CAS 循环)实现,避免 mutex 锁竞争(如用
std::atomic维护栈顶) - 慎用
std::shared_mutex或读写锁——对高频分配场景仍是重开销
与 RAII 和现代 C++ 集成(安全且易用)
内存池不该破坏 C++ 的资源管理习惯。可通过定制分配器(Allocator)接入 STL 容器,或封装智能指针语义。
- 实现符合 C++ Allocator 要求 的类,重载
allocate()/deallocate(),传给std::vector> - 不建议直接重载全局
operator new—— 影响范围不可控,调试困难 - 提供
make_unique_in_pool工厂函数,返回(pool) std::unique_ptr,析构时自动归还内存 - 池对象自身用 RAII 管理(构造预分配,析构释放全部内存),避免裸指针泄漏
基本上就这些。一个实用的内存池不需要面面俱到,关键是根据你的热点对象尺寸、线程模型和生命周期特征做裁剪。比起堆上分配快 3~10 倍很常见,但前提是别把它当成黑盒——得清楚它在哪归还、是否线程安全、有没有隐式扩容。不复杂但容易忽略。










