C++ PMR多态内存资源选型:支持按需释放闲置内存的方案问询
符合需求的PMR内存资源实现方案
标准库自带的PMR内存资源确实没有主动返还闲置内存的能力,你可以通过自定义std::pmr::memory_resource子类实现需求,既保留池化内存的局部性优化收益,又能在低峰期释放多余内存降低占用。
核心实现逻辑
- 内部维护分大小类的空闲内存池,对每个大小类的空闲块设置最大缓存阈值,超过阈值的空闲块在归还时直接调用上游的
deallocate释放回上游 - 额外提供手动
trim()接口,调用时释放所有超过最小保留量的空闲内存,你可以在守护进程的低峰调度逻辑里定时/按需调用该接口,效果完全等价于按需调用malloc_trim - 线程安全版本可在内部加读写锁实现,性能和标准的
synchronized_pool_resource接近,仅多一次阈值判断的开销,对整体性能影响极小
极简示例实现
#include <memory_resource> #include <mutex> #include <vector> #include <unordered_map> class trimable_pool_resource : public std::pmr::memory_resource { private: std::pmr::memory_resource* upstream; std::mutex mtx; // 每个大小类最多缓存的块数,可根据业务调整 static constexpr size_t max_cached_blocks_per_size = 8; // 大小类 -> 空闲块列表 std::unordered_map<size_t, std::vector<void*>> free_lists; protected: void* do_allocate(size_t bytes, size_t alignment) override { std::lock_guard lk(mtx); // 优先从空闲列表取已缓存的块 if (auto it = free_lists.find(bytes); it != free_lists.end() && !it->second.empty()) { void* ptr = it->second.back(); it->second.pop_back(); return ptr; } // 无可用缓存则从上游分配 return upstream->allocate(bytes, alignment); } void do_deallocate(void* p, size_t bytes, size_t alignment) override { std::lock_guard lk(mtx); auto& list = free_lists[bytes]; if (list.size() < max_cached_blocks_per_size) { // 未达缓存阈值则留存 list.push_back(p); return; } // 超过阈值直接返还上游 upstream->deallocate(p, bytes, alignment); } bool do_is_equal(const std::pmr::memory_resource& other) const noexcept override { return this == &other; } public: explicit trimable_pool_resource(std::pmr::memory_resource* upstream = std::pmr::get_default_resource()) : upstream(upstream) {} // 手动裁剪接口,低负载时调用即可释放多余闲置内存 void trim() { std::lock_guard lk(mtx); for (auto& [size, list] : free_lists) { // 每个大小类仅保留2块最小缓存,其余全部释放,阈值可自行调整 while (list.size() > 2) { void* p = list.back(); list.pop_back(); upstream->deallocate(p, size, alignof(std::max_align_t)); } } } ~trimable_pool_resource() override { // 析构时释放所有缓存的内存 trim(); for (auto& [size, list] : free_lists) { for (void* p : list) { upstream->deallocate(p, size, alignof(std::max_align_t)); } } } };
使用说明
- 上述实现可以直接替换你当前使用的
synchronized_pool_resource/unsynchronized_pool_resource,内存局部性优化效果和标准池化资源一致 - 你可以在守护进程的低负载检测逻辑中直接调用
trim()方法,即可立刻释放多余的闲置内存回上游,完全符合你按需降低内存占用的需求 - 可通过修改
max_cached_blocks_per_size和trim方法中的保留阈值,平衡内存占用和分配性能 - 如果仅在单线程场景使用,可以去掉内部的mutex锁,性能和
unsynchronized_pool_resource完全一致
内容的提问来源于stack exchange,提问作者戴均維
相关产品推荐
相关产品推荐

