# 高吞吐无锁内存分配引擎 **Repository Path**: Accsen/High-concurrency-memory-pool ## Basic Information - **Project Name**: 高吞吐无锁内存分配引擎 - **Description**: 本项目实现了一款高吞吐无锁内存分配引擎,核心设计理念源自 Google 的 tcmalloc,通过深度优化,致力于为多线程环境提供高效、稳定的内存管理方案,旨在解决传统内存分配方式在高并发场景下的性能瓶颈问题。项目完整代码可在项目仓库获取。 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-02-27 - **Last Updated**: 2026-03-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 高吞吐无锁内存分配引擎 本项目实现了一款高吞吐无锁内存分配引擎,核心设计理念源自 Google 的 tcmalloc,通过深度优化,致力于为多线程环境提供高效、稳定的内存管理方案,旨在解决传统内存分配方式在高并发场景下的性能瓶颈问题。 ## 项目核心亮点 ### 无锁设计,高并发高效处理 采用线程局部存储(TLS)技术,为每个线程分配专属的缓存(Thread Cache)。这一设计使得在大部分内存分配场景下,线程无需竞争锁资源,极大地减少了锁冲突带来的性能损耗,显著提升了高并发环境下的内存分配效率。 ### 精细内存管理,降低碎片率 内存分配引擎通过精心设计的内存池架构,包括 Thread Cache、Central Cache 和 Page Cache,实现了对内存的分层管理。Page Cache 以页为单位进行内存分配和回收,并在回收时尝试合并相邻的空闲内存块,有效减少了内存碎片的产生,提高了内存的利用率。 ### 自适应内存分配策略 Central Cache 采用慢开始反馈调节算法,根据 Thread Cache 的内存需求动态调整分配的内存数量。在面对不同大小的内存请求时,能够智能地给出合适数量的内存块,既避免了一次性分配过多内存造成浪费,又防止分配不足导致频繁申请,进一步优化了内存分配的效率和资源利用率。 ## 技术实现细节 ### 定长内存池基础 **定长实现机制**:利用模板技术,通过非类型模板参数或模板参数指定对象大小,实现对固定大小内存块的高效管理。在不同操作系统平台下,封装了相应的内存申请函数(如 Windows 下的 VirtualAlloc,Linux 下的 brk 或 mmap),确保内存池在不同环境下的兼容性和稳定性。 **内存块管理策略**:定长内存池通过自由链表管理释放的内存块。在 32 位和 64 位平台下,巧妙利用内存块的前 4 字节或 8 字节存储下一个内存块的地址,实现了简单而高效的链表操作。同时,在申请和释放内存块时,会根据平台指针大小进行合理的内存对齐,确保内存块的正确管理和使用。 ### 高并发内存池架构 - **Thread Cache**:作为每个线程的专属缓存,采用哈希桶结构管理不同大小的内存块。通过特定的字节对齐规则,将不同大小的内存请求映射到相应的哈希桶中,减少了自由链表的数量,降低了内存开销。当线程申请内存时,优先从 Thread Cache 中获取,若对应哈希桶为空,则向 Central Cache 申请。 - **Central Cache**:作为所有线程共享的缓存,其结构与 Thread Cache 相似,但每个桶中存储的是 Span。Span 用于管理以页为单位的大块内存,内部包含自由链表存储切分好的内存块。Central Cache 通过桶锁机制保证线程安全,只有当多个线程同时访问同一个桶时才会加锁,有效降低了锁竞争的概率。 - **Page Cache**:负责提供大块内存,采用哈希桶结构存储不同页数的 Span。其哈希桶映射规则采用直接定址法,方便快速定位和管理不同页数的内存块。当 Central Cache 需要内存时,Page Cache 会分配相应页数的 Span;当 Central Cache 归还 Span 时,Page Cache 会尝试合并相邻的 Span,以减少内存碎片。 ### 内存申请与释放流程 **申请流程**:线程调用 `ConcurrentAlloc` 函数申请内存时,首先判断申请内存的大小。若小于等于 256KB,则通过 TLS 获取专属的 Thread Cache 进行分配;若大于 256KB,则直接向 Page Cache 申请。在申请过程中,Thread Cache、Central Cache 和 Page Cache 会协同工作,确保内存的有效分配。 **释放流程**:线程调用 `ConcurrentFree` 函数释放内存时,同样根据内存大小决定释放方式。小于等于 256KB 的内存块释放给 Thread Cache,当 Thread Cache 中对应自由链表长度超过一定阈值时,会将部分内存块还给 Central Cache;大于 256KB 的内存块则直接释放给 Page Cache 或堆。Central Cache 在回收内存块时,若某个 Span 的 `_useCount` 减为 0,则将该 Span 还给 Page Cache,Page Cache 会对归还的 Span 进行合并操作,以优化内存布局。 ### 性能优化与改进 1. **脱离传统内存分配方式**:在项目实现过程中,完全避免了对传统 malloc 函数的调用,转而使用定长内存池进行内存分配。这一举措不仅提高了内存分配的效率,还增强了项目在高并发场景下的独立性和稳定性。 2. **优化内存释放操作**:在 Span 结构中增加 `_objSize` 成员,用于记录 Span 管理的内存块被切成的对象大小。这一优化使得在释放对象时,无需再传入对象大小,简化了释放操作流程,提高了代码的可读性和性能。 3. **基于基数树的映射优化**:通过性能分析发现,锁竞争是影响性能的关键因素。为此,项目使用基数树(如单层、二层、三层基数树,根据平台选择)优化页号与 Span 的映射关系读取操作。基数树的使用使得在读取映射关系时无需加锁,大大提高了内存分配和释放的效率。在 32 位平台下,可选择单层或二层基数树;64 位平台下,使用三层基数树,以适应不同平台的内存管理需求。 ## 项目结构 ``` biproject/ ├── Benchmark.cpp # 性能基准测试 ├── CentralCache.cpp # Central Cache 实现 ├── CentralCache.h # Central Cache 头文件 ├── Commond.h # 公共定义和工具类 ├── ConCurrentAlloc.h # 并发内存分配接口 ├── ObjectPool.h # 对象池实现 ├── PageCache.cpp # Page Cache 实现 ├── PageCache.h # Page Cache 头文件 ├── PageMap.h # 基数树映射实现 ├── ThreadCache.cpp # Thread Cache 实现 ├── ThreadCache.h # Thread Cache 头文件 └── UnitTess.cpp # 单元测试 Fixed_length_memory_pool/ ├── ObjectPool.h # 定长内存池 └── test.cc # 定长内存池测试 ``` ## 项目测试与验证 ### 单线程测试 通过编写单线程测试用例,对内存池在单线程环境下的内存分配和释放逻辑进行了全面验证。测试过程中,多次申请和释放不同大小的内存块,检查内存块的分配来源(Thread Cache、Central Cache 或 Page Cache)以及内存块的合并和管理情况,确保了内存池在单线程环境下的正确性和稳定性。 ### 多线程测试 在多线程场景下,通过对比本内存分配引擎与传统 malloc 函数的性能,对项目进行了严格的测试。测试过程中,设置不同的线程数、轮次和单轮申请释放次数,使用 `BenchmarkMalloc` 和 `BenchmarkConcurrentMalloc` 函数分别测试 malloc 和本内存分配引擎的内存分配和释放时间。测试结果表明,在申请释放不同大小内存时,本内存分配引擎的效率有显著提升。 ## 使用说明环境 ### 编译 - C++11 及以上版本 - 支持 Windows 和 Linux 平台 ### 快速开始 ```cpp #include "ConCurrentAlloc.h" // 分配内存 void* ptr = ConcurrentAlloc(1024); // 申请 1024 字节 // 释放内存 ConcurrentFree(ptr, 1024); // 释放内存 ``` ### 性能测试 运行 `Benchmark.cpp` 可以对比本内存分配引擎与 malloc 的性能差异: ```bash # 编译后运行 ./biproject ``` ## 许可证 本项目仅供学习交流使用。