可嵌入式全能内存池库。把常见的多种分配模型实现到一个库里:固定对象池、Arena/线性分配、size class 通用小对象池、线程本地缓存、跨线程释放、PMR 适配、STL allocator、C ABI,以及可选的 malloc / operator new 替换。
- 多分配模型:
fixed_pool、object_pool<T>、linear_arena、arena(typed,带析构登记)、size classmemory_pool。 - 并发友好:线程本地缓存(thread cache)+ 中心缓存(central cache)+ 跨线程释放(remote free / owner token)。
- 标准接口适配:
std::pmr::memory_resource、pool_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./build/ump_memory_pool_bench输出 CSV,便于存档与对比:
scenario,operations,microseconds,ops_per_second
fixed_object,...
random_small,...
arena,...
pmr_vector,...
multithread,...
remote_free,...
cmake --preset asan-ubsan
cmake --build --preset asan-ubsan
ctest --preset asan-ubsan底层开关为 UMP_ENABLE_ASAN / UMP_ENABLE_UBSAN。asan-ubsan test preset 设置 ASAN_OPTIONS=detect_leaks=0,规避部分受 ptrace 包裹环境的 LeakSanitizer 限制;地址与未定义行为检查仍启用。ASan runtime 自身会 interpose malloc 符号,因此 libc interpose / preload 烟测在该 preset 下只构建、不运行。
#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();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); // 回滚到检查点#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)};#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 边界 |
下面只列出当前实现会读取并生效的字段,避免展示无效或预留配置。
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 元数据。
#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。
#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);还提供 calloc、aligned_alloc、usable_size、stats、trim。使用进程内默认 memory_pool,该默认池故意不参与静态析构,规避退出顺序问题。
target_link_libraries(app PRIVATE universal_memory_pool::global_new_delete)覆盖普通 / 数组 / nothrow / sized / over-aligned 全套全局签名,转发到 ump::malloc_shim;检测到 shim 内部初始化或递归进入时回退到 system allocation。
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_appcmake --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)tests/ 下为 CTest 套件(基础正确性、边界、并发、debug、C ABI、radix map、metadata allocator、RSS/purge 等),通过 tests/test_runner.cpp 统一注册运行。.github/workflows/ci.yml 覆盖 gcc-debug、clang-debug、clang-asan-ubsan 三个 job;CI 中 benchmark 仅作为构建/烟测目标,不作为性能结论。
cd build && ctest --output-on-failure知识星球: “奔跑中cpp / c++” 所有 ,
阿甘微信:LLqueww
商业使用前请联系我方授权 一旦发现侵权行为,将依法追究法律责任
(对于公司法律事务已有对接律师,敬请告知)