memory-pool
从“无锁应该更快”的直觉出发,记录一次内存池并发压测中暴露出的 ABA 问题,以及对内存复用边界的重新理解。
分桶数量64 个 size-class
核心结构CAS 无锁 free list
当前状态实验复盘与后续修复进行中
项目做了什么
内存池按申请大小把对象路由到不同的固定尺寸分桶,单个分桶维护空闲块链表;超过当前分桶范围的请求再走普通分配路径。目标不是简单宣称“比 malloc 快”,而是观察预分配、地址复用和跨线程释放分别带来什么影响。
目前项目仍在实验阶段,页面保留问题现场,不把未完成的修复写成最终能力。
问题现场:ABA
Thread A: 读到 freeList = X,准备 CAS Thread B: 摘走 X,用户数据覆盖 X->next Thread B: 释放 X,freeList 又回到 X Thread A: 看到头仍是 X,CAS 使用已经过期的 next 结果:链表头可能被写成 0x1,后续 pop 触发崩溃
CAS 只比较指针值,不知道同一个地址在两次比较之间已经被摘走、改写又放回。内存池的地址复用正好放大了这个窗口,这也是单线程测试通过而多线程压测失败的原因。
技术取舍
- CAS free list:减少显式锁,但需要同时处理节点生命周期、用户数据覆盖和 ABA 风险。
- size-class 分桶:固定规格便于复用和定位,但会带来内部碎片与容量边界设计问题。
- 问题优先于结论:当前记录重点是崩溃复现、gdb 现场和根因链路,性能结论必须绑定线程数、对象大小和释放方等实验条件。
下一步
后续会继续对比版本号指针、Hazard Pointer 和 RCU 等 ABA 处理方案,并补充跨线程分配释放与 glibc tcache 的对照 benchmark。相关实验完成前,项目状态保持“进行中”。