Skip to content

cpp-agan-team/All-purpose-Memory-Pool

Repository files navigation

universal_memory_pool

可嵌入式全能内存池库。把常见的多种分配模型实现到一个库里:固定对象池、Arena/线性分配、size class 通用小对象池、线程本地缓存、跨线程释放、PMR 适配、STL allocator、C ABI,以及可选的 malloc / operator new 替换。

默认路径轻量、低锁、易用;调试、统计、安全等高级能力按需开启,不拖累普通分配场景。

核心特性

  • 多分配模型fixed_poolobject_pool<T>linear_arenaarena(typed,带析构登记)、size class memory_pool
  • 并发友好:线程本地缓存(thread cache)+ 中心缓存(central cache)+ 跨线程释放(remote free / owner token)。
  • 标准接口适配std::pmr::memory_resourcepool_allocator<T>cache_aligned_allocator<T>
  • 可观测性stats() 结构体、dump_stats() 文本报告、dump_json() 机器可读输出。
  • 调试与安全debug_mode::light/full,提供 redzone、canary、poison、quarantine、double-free / invalid-free 检测、leak report。
  • 内存回收trim() / purge(),lazy / eager purge 策略,dirty page 与 RSS 观测。
  • 可插拔后端page_provider 抽象,POSIX 走 mmap/madvise,Windows 走 VirtualAlloc
  • C ABI 与替换层:稳定 C 接口、显式 malloc shim、可选全局 operator new/delete、可选 libc interpose 与 LD_PRELOAD 共享库。

架构

三层缓存结构吸收了 TCMalloc / mimalloc / snmalloc 的核心设计:前端线程本地无锁快路径,中端按 size class 分锁批量补充,后端统一管理页与 span。

+-----------------------------------------------------------+
| Public API                                                |
|  memory_pool / object_pool<T> / arena / pmr / allocator   |
|  fixed_pool / C ABI / malloc shim                         |
+-----------------------------------------------------------+
| Front-end (per-thread, 无锁快路径)                        |
|  thread_cache  ·  owner_token  ·  remote free queue       |
+-----------------------------------------------------------+
| Middle-end (按 size class 分锁)                           |
|  central_cache  ·  size_class_map  ·  span                |
+-----------------------------------------------------------+
| Back-end                                                  |
|  page_provider  ·  radix page map  ·  metadata_allocator  |
|  purge / large allocation                                 |
+-----------------------------------------------------------+
| OS                                                        |
|  mmap/munmap/madvise  ·  VirtualAlloc/VirtualFree         |
+-----------------------------------------------------------+

关键机制:

  • size class:小对象按密集 size class 桶映射到内部 slot,大对象绕过小对象池直接走 page provider。
  • span:一段连续页,只服务单一 size class,内部维护空闲链表与归属计数。
  • radix page map:从任意用户指针定位 span / allocation 元数据,支撑 unsized deallocate(ptr) 和 invalid-free 检测。
  • owner token:span 记录 owner token 而非裸 thread_cache 指针;跨线程释放进入 owner 的 remote queue,线程退出后 token 转为 abandoned,释放仍有安全落点。
  • metadata_allocator:内部元数据(span / page map 节点 / 缓存结构)由独立的 bootstrap 分配器服务,避免自举递归。

代码结构

include/universal_memory_pool/
  memory_pool.hpp        聚合头 + memory_pool 类
  options.hpp            pool_options 与策略枚举
  stats.hpp              memory_pool_stats 指标结构
  size_class.hpp         size class 映射
  page_provider.hpp      OS 页抽象与默认实现声明
  fixed_pool.hpp         固定大小对象池
  object_pool.hpp        强类型对象池 object_pool<T>
  arena.hpp              linear_arena 与 typed arena
  pmr.hpp                std::pmr::memory_resource 适配
  allocator.hpp          pool_allocator<T> / cache_aligned_allocator<T>
  malloc_shim.hpp        显式 malloc 风格 façade
  system_stats.hpp       进程 RSS 快照
  c_api.h                C ABI
  detail/
    alignment.hpp           对齐与溢出检查工具
    metadata_allocator.hpp  元数据自举分配器
    metadata_stl_allocator.hpp  转发到 metadata_allocator 的 STL allocator
    radix_page_map.hpp      指针 → span/metadata 的 radix 定位

src/
  memory_pool.cpp        核心:size class 池、thread/central cache、remote free、purge、debug
  arena.cpp              arena / linear_arena 实现
  page_provider.cpp      默认页提供器(mmap / VirtualAlloc)
  pmr.cpp                PMR resource 实现
  c_api.cpp              C ABI 实现
  malloc_shim.cpp        malloc shim + 进程默认池
  global_new_delete.cpp  可选:全局 operator new/delete 替换
  libc_interpose.cpp     可选:libc malloc/free 符号替换
  system_stats.cpp       RSS 快照实现

examples/                12 个可运行示例(见下)
tests/                   CTest 测试套件 + runner
benchmarks/
  memory_pool_bench.cpp  CSV 输出的对比 benchmark
cmake/                   install/export 配置模板
CMakeLists.txt           构建定义
CMakePresets.json        debug / asan-ubsan preset

编译与运行

要求:C++20 编译器(GCC 12+ / Clang 15+),CMake 3.20+。

构建与测试

cmake -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j$(nproc)
cd build && ctest --output-on-failure

也可使用 CMake preset:

cmake --preset debug
cmake --build --preset debug
ctest --preset debug

运行示例

构建后,可执行文件位于 build/

./build/ump_basic_example         # allocate/deallocate 基础用法
./build/ump_object_pool_example   # object_pool<T> 构造/析构
./build/ump_arena_request_example # arena 请求级生命周期
./build/ump_pmr_vector_example    # std::pmr::vector 接入
./build/ump_stats_example         # stats 输出
./build/ump_debug_checks_example  # debug full 错误检测
./build/ump_trim_example          # trim 回收
./build/ump_rss_purge_example     # RSS / purge 观测
./build/ump_malloc_shim_example   # malloc 风格 façade
./build/ump_multithread_example   # 多线程分配释放
./build/ump_remote_free_example   # 跨线程释放
./build/ump_c_api_example         # C ABI

运行 benchmark

./build/ump_memory_pool_bench

输出 CSV,便于存档与对比:

scenario,operations,microseconds,ops_per_second
fixed_object,...
random_small,...
arena,...
pmr_vector,...
multithread,...
remote_free,...

Sanitizer

cmake --preset asan-ubsan
cmake --build --preset asan-ubsan
ctest --preset asan-ubsan

底层开关为 UMP_ENABLE_ASAN / UMP_ENABLE_UBSANasan-ubsan test preset 设置 ASAN_OPTIONS=detect_leaks=0,规避部分受 ptrace 包裹环境的 LeakSanitizer 限制;地址与未定义行为检查仍启用。ASan runtime 自身会 interpose malloc 符号,因此 libc interpose / preload 烟测在该 preset 下只构建、不运行。


API 速览

C++ 高层

#include "universal_memory_pool/memory_pool.hpp"

ump::memory_pool pool;

// 裸内存
void* p = pool.allocate(128);          // 默认对齐
void* q = pool.allocate(96, 64);       // 显式 64 字节对齐
pool.deallocate(p);                    // 易用路径,经 page map 定位
pool.deallocate_sized(q, 96, 64);      // 高性能路径,调用方已知 size/alignment

// 强类型对象
auto* obj = pool.create<MyType>(args...);
pool.destroy(obj);

// 观测与回收
auto s = pool.stats();
pool.dump_stats(std::cout);
std::string json = pool.dump_json();
pool.trim();

object_pool / arena

ump::object_pool<Node> nodes;
Node* n = nodes.create(1, 2);
nodes.destroy(n);

ump::arena arena;                       // 请求级 / 帧级批量对象
auto* a = arena.make<Widget>(...);      // 非平凡析构会自动登记
arena.reset();                          // 一次性析构并回收

ump::linear_arena bump(64 * 1024);      // 纯 bump pointer,最快
auto m = bump.mark();
bump.allocate(256);
bump.rewind(m);                         // 回滚到检查点

PMR / STL allocator

#include "universal_memory_pool/pmr.hpp"
#include "universal_memory_pool/allocator.hpp"

ump::memory_pool pool;
ump::pool_memory_resource resource(pool);
std::pmr::vector<int> v(&resource);

std::list<int, ump::pool_allocator<int>> lst{ump::pool_allocator<int>(pool)};

C ABI

#include "universal_memory_pool/c_api.h"

ump_pool_options options;
ump_pool_options_init(&options);              // 填入 struct_size

ump_pool* pool = ump_pool_create(&options);
void* ptr     = ump_alloc(pool, 128);
void* aligned = ump_aligned_alloc(pool, 64, 96);
void* zeroed  = ump_calloc(pool, 16, 8);
ptr = ump_realloc(pool, ptr, 256);

ump_free_sized_aligned(pool, aligned, 96, 64);
ump_free_sized(pool, ptr, 256);
ump_free(pool, zeroed);

ump_pool_stats stats;
ump_pool_stats_init(&stats);
ump_pool_get_stats(pool, &stats);

ump_pool_destroy(pool);

ump_pool_options::struct_size / ump_pool_stats::struct_size*_init() 填入,库据此兼容未来新增字段。ump_realloc(pool, ptr, 0) 释放 ptr 并返回 NULL;过对齐分配的热路径 sized free 用 ump_free_sized_aligned()


适用场景及原因

场景 推荐 原因
大量同类型对象(节点、消息、任务) object_pool<T> 固定大小空闲链表,分配/释放近乎 O(1),无 size class 查找开销
小对象高频分配释放 memory_pool(size class) 按 size class 复用 slot,避免频繁 new/delete 和系统调用
请求级 / 帧级批量对象 arena 生命周期一致,结束时一次性 reset() 释放,析构成本与对象数解耦
编译器 AST / 解析器临时对象 linear_arena 纯 bump pointer 分配最快,mark/rewind 支持检查点回滚
标准容器内存 pool_memory_resource / pool_allocator<T> 无侵入接入 std::pmr 与 STL 容器,复用池的缓存与统计
线程 A 分配、线程 B 释放 remote free(默认开启) 释放进入 owner remote queue,不抢 owner 锁,避免跨线程竞争
多线程高并发分配 memory_pool + thread cache 线程本地快路径减少锁争用,central cache 按 size class 分锁
多线程频繁写的相邻对象 cache_aligned_allocator<T> 对象按 cache line 对齐,避免 false sharing
长期运行服务(关注 RSS 回落) purge_policy::eager + trim() 空 span 及时 purge/释放,峰值后内存可回落
调试越界 / double free / 泄漏 debug_mode::full redzone、canary、quarantine、poison、leak report,与 release 快路径隔离
C 代码 / 跨语言边界 C ABI opaque handle + struct_size 兼容,稳定的 ABI 边界

配置(pool_options)

下面只列出当前实现会读取并生效的字段,避免展示无效或预留配置。

ump::pool_options options;
options.max_small_block_size = 32 * 1024;   // 小/大对象分界
options.span_size            = 64 * 1024;   // 每个 span 的目标大小
options.thread_cache_limit   = 2 * 1024 * 1024;  // 每线程缓存字节上限
options.central_cache_limit  = 64 * 1024 * 1024; // central cache 软上限
options.min_slot_size        = alignof(std::max_align_t); // slot 下限
options.purge                = ump::purge_policy::lazy;
options.debug                = ump::debug_mode::off;
options.cache_aligned        = false;       // true 时有效分配提升到 64 字节对齐
options.enable_thread_cache  = true;
options.enable_remote_free   = true;
options.enable_stats         = true;        // false 关闭可选统计维护
options.provider             = nullptr;     // 自定义 page_provider

ump::memory_pool pool(options);

enable_stats=false 关闭 allocation / thread-cache / remote-free / span / metadata 等可选统计的维护,但保留释放所必需的 allocation 元数据。

自定义 page provider

#include "universal_memory_pool/page_provider.hpp"

ump::pool_options options;
options.provider = &custom_provider;   // 生命周期必须长于使用它的 pool
ump::memory_pool pool(options);

page_provider 提供 reserve/commit/decommit/reset/release/page_size 边界。默认实现 POSIX 走 mmap/munmap/madvise,Windows 走 VirtualAlloc/VirtualFree;超页对齐或不支持的平台回退到标准 aligned allocation。小对象 central span 与大对象都经 provider。测试可注入 mock provider 模拟分配失败。


可选替换层

默认库替换全局 operator new/delete 或 libc 符号。需要时显式链接 opt-in target。

显式 malloc shim(不替换符号)

#include "universal_memory_pool/malloc_shim.hpp"

void* p = ump::malloc_shim::malloc(128);
p = ump::malloc_shim::realloc(p, 256);
ump::malloc_shim::free(p);

还提供 callocaligned_allocusable_sizestatstrim。使用进程内默认 memory_pool,该默认池故意不参与静态析构,规避退出顺序问题。

全局 operator new/delete 替换

target_link_libraries(app PRIVATE universal_memory_pool::global_new_delete)

覆盖普通 / 数组 / nothrow / sized / over-aligned 全套全局签名,转发到 ump::malloc_shim;检测到 shim 内部初始化或递归进入时回退到 system allocation。

libc interpose 与 LD_PRELOAD

target_link_libraries(app PRIVATE universal_memory_pool::libc_interpose)

定义 malloc/free/calloc/realloc/aligned_alloc,POSIX 下还有 posix_memalign。检测到递归、shim 初始化、默认池初始化或 fork 后 child 时回退到 OS mapping fallback。

Linux/POSIX 还提供 preload 共享库:

LD_PRELOAD=/path/to/libuniversal_memory_pool_preload.so ./your_app

安装与下游集成

cmake --install build --prefix /tmp/ump-install

下游 CMake 项目:

find_package(universal_memory_pool CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE universal_memory_pool::universal_memory_pool)

测试与 CI

tests/ 下为 CTest 套件(基础正确性、边界、并发、debug、C ABI、radix map、metadata allocator、RSS/purge 等),通过 tests/test_runner.cpp 统一注册运行。.github/workflows/ci.yml 覆盖 gcc-debugclang-debugclang-asan-ubsan 三个 job;CI 中 benchmark 仅作为构建/烟测目标,不作为性能结论。

cd build && ctest --output-on-failure

许可说明

知识星球: “奔跑中cpp / c++” 所有 ,

阿甘微信:LLqueww

商业使用前请联系我方授权 一旦发现侵权行为,将依法追究法律责任

(对于公司法律事务已有对接律师,敬请告知)

About

All-in-one embedded memory pool: fixed pool, arena, size-class, thread cache, cross-thread free, PMR & STL allocator, C ABI, optional malloc/new override.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors