# tcmalloc **Repository Path**: bai_xiaobaila/tcmalloc ## Basic Information - **Project Name**: tcmalloc - **Description**: tcmalloc项目仓库 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-03-08 - **Last Updated**: 2025-05-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MyMemoryPool - 高性能内存池实现 ## 项目简介 MyMemoryPool是一个基于tcmalloc思想实现的高性能内存池,采用三级缓存架构设计,针对频繁内存分配和释放的场景进行了优化。本项目实现了内存的高效管理,减少了内存碎片,提高了内存分配效率。 ## 核心架构 ### 三级缓存设计 1. **ThreadCache(线程缓存)** - 每个线程独享的缓存层 - 使用TLS(Thread Local Storage)实现,避免线程同步开销 - 支持最大256KB的内存分配 - 包含208个自由链表,对应不同大小的内存块 2. **CentralCache(中心缓存)** - 采用单例模式实现 - 作为ThreadCache和PageCache之间的中间层 - 负责内存的批量分配和回收 - 实现内存的均衡分配 3. **PageCache(页缓存)** - 管理以页为单位的内存(8KB/页) - 支持Span的合并和拆分 - 使用哈希表记录页号到Span的映射 - 实现大块内存的管理 ### 内存申请和释放流程 #### 内存申请流程 1. **小内存申请(≤256KB)** ```cpp // 通过TLS获取线程专属的ThreadCache if (pTLSThreadCache == nullptr) { pTLSThreadCache = new ThreadCache; } return pTLSThreadCache->Allocate(size); ``` - 首先检查线程本地缓存(ThreadCache) - ThreadCache包含208个自由链表,对应不同大小的内存块 - 如果ThreadCache中没有足够内存: 1. 向CentralCache申请批量内存 2. CentralCache从PageCache获取新的Span 3. 将Span切分成对应大小的内存块 4. 返回部分内存块给ThreadCache,剩余部分保留在CentralCache - 分配过程无锁,性能最优 2. **大内存申请(>256KB)** ```cpp // 直接向PageCache申请 size_t alignSize = SizeClass::RoundUp(size); size_t kpage = alignSize >> PAGE_SHIFT; PageCache::GetInstance()->_pageMtx.lock(); Span* span = PageCache::GetInstance()->NewSpan(kpage); span->_objSize = size; PageCache::GetInstance()->_pageMtx.unlock(); ``` - 直接向PageCache申请整页内存 - 申请过程: 1. 计算需要的页数(kpage) 2. 如果kpage > 128,直接调用系统接口分配 3. 否则在PageCache中查找合适的Span: - 优先查找大小刚好匹配的Span - 如果没有,查找更大的Span并切分 - 如果都没有,申请新的128页Span并切分 - 需要加锁保护,性能相对较低 - 按页对齐,减少内存碎片 #### 内存释放流程 1. **小内存释放(≤256KB)** ```cpp // 释放到ThreadCache pTLSThreadCache->Deallocate(ptr, size); ``` - 优先释放到ThreadCache对应的自由链表 - 当ThreadCache中对应自由链表过长时: 1. 回收部分内存到CentralCache 2. CentralCache将内存块重新组织到对应的Span中 - 释放过程无锁,性能最优 2. **大内存释放(>256KB)** ```cpp // 直接释放到PageCache PageCache::GetInstance()->_pageMtx.lock(); PageCache::GetInstance()->ReleaseSpanToPageCache(span); PageCache::GetInstance()->_pageMtx.unlock(); ``` - 直接释放到PageCache - 释放过程: 1. 如果Span大小超过128页,直接释放回系统 2. 否则尝试与相邻的Span合并: - 检查前一个Span是否可合并 - 检查后一个Span是否可合并 - 合并后的Span重新插入到对应大小的SpanList中 - 需要加锁保护,性能相对较低 #### 内存分配策略 - **ThreadCache层**: - 管理≤256KB的内存分配 - 使用208个自由链表,对应不同大小的内存块 - 无锁操作,性能最优 - 使用TLS确保线程安全 - **CentralCache层**: - 作为ThreadCache和PageCache的中间层 - 管理Span的切分和合并 - 实现内存的均衡分配 - 使用对象池(ObjectPool)优化Span对象的分配 - **PageCache层**: - 管理>256KB的内存分配 - 以页(8KB)为单位管理内存 - 支持Span的合并,减少内存碎片 - 使用哈希表(_idSpanMap)记录页号到Span的映射 - 使用互斥锁保护并发访问 ## 核心特性 ### 1. 智能内存对齐策略 ```cpp [1,128]字节:8字节对齐 [129,1024]字节:16字节对齐 [1025,8K]字节:128字节对齐 [8K+1,64K]字节:1024字节对齐 [64K+1,256K]字节:8K字节对齐 ``` - 通过精细的对齐策略,将内存碎片控制在10%以内 - 使用位运算优化对齐计算,提高性能 ### 2. 高效的内存管理机制 - 使用自由链表管理内存块,实现O(1)时间复杂度的分配和回收 - 实现批量分配和回收机制,减少系统调用 - 支持内存的合并和拆分,减少内存碎片 ### 3. 性能优化设计 - 使用TLS避免线程同步开销 - 采用位运算代替取模运算 - 实现慢启动机制,避免内存浪费 - 使用对象池优化Span对象的分配 ## 独特之处 1. **精细的内存分级** - 通过208个自由链表实现精细的内存管理 - 不同大小的内存采用不同的对齐策略,优化内存利用率 2. **智能的批量处理** - 实现了动态的批量分配策略 - 根据内存大小自动调整批量分配数量 3. **高效的内存回收** - 支持Span的合并,减少内存碎片 - 实现了多级缓存之间的内存均衡 ## 当前局限 1. **内存大小限制** - 目前最大支持256KB的内存分配 - 超过此限制的内存分配会直接使用系统分配 2. **并发处理** - 虽然使用TLS避免了线程同步,但在高并发场景下可能存在性能瓶颈 - PageCache的锁粒度较大,可能影响性能 3. **内存碎片** - 虽然通过对齐策略减少了碎片,但仍存在一定的内存浪费 - 大块内存的分配和回收可能产生碎片 ## 改进方向 1. **性能优化** - 实现更细粒度的锁机制 - 优化PageCache的并发访问 - 引入内存预分配机制 2. **功能扩展** - 支持更大的内存分配 - 实现内存池的动态扩容 - 添加内存使用统计和监控 3. **内存管理优化** - 实现更智能的内存合并策略 - 优化大块内存的管理 - 添加内存碎片整理机制 ## 使用示例 ```cpp // 内存分配 void* ptr = ConcurrentAlloc(1); // 内存释放 ConcurrentFree(ptr); ``` ## 贡献指南 欢迎提交Issue和Pull Request来帮助改进项目。 ## 许可证 Mulan Permissive Software License