You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何借助std::pmr实现对象池?求std::pmr实际应用经验

解决方案:组合std::pmr资源实现可复用对象池

你遇到的核心问题是**monotonic_buffer_resource仅支持单向分配、不支持内存复用**,而标准库提供的池化资源(unsynchronized_pool_resource/synchronized_pool_resource)本身不直接绑定固定缓冲区,但可以通过指定上游内存资源的方式,让池化资源从你预分配的缓冲区中获取内存,同时实现内存的复用。

具体实现步骤:

  • 预分配一块固定大小的缓冲区(栈上数组、堆分配内存或内存映射区域均可)。
  • 用这块缓冲区初始化monotonic_buffer_resource,作为池化资源的上游——它负责将预分配的缓冲区提供给池化资源使用。
  • 初始化unsynchronized_pool_resource(单线程场景)或synchronized_pool_resource(多线程场景),将上述monotonic_buffer_resource作为其上游资源。
  • 基于池化资源实现对象池:利用placement new在分配的内存上构造对象,对象销毁时显式调用析构函数,并将内存归还给池化资源。

代码示例:

#include <memory_resource>
#include <array>
#include <cstddef>

// 根据对象大小和数量调整预分配缓冲区大小
constexpr size_t BUFFER_SIZE = 1024 * 64;
alignas(std::max_align_t) std::array<char, BUFFER_SIZE> buffer;

class ObjectPool {
public:
    ObjectPool() 
        : upstream_{buffer.data(), buffer.size()},
          pool_{&upstream_} {}

    // 分配并构造对象
    template<typename T, typename... Args>
    T* allocate(Args&&... args) {
        void* mem = pool_.allocate(sizeof(T), alignof(T));
        return new(mem) T(std::forward<Args>(args)...);
    }

    // 销毁并释放对象
    template<typename T>
    void deallocate(T* obj) {
        obj->~T();
        pool_.deallocate(obj, sizeof(T), alignof(T));
    }

private:
    std::pmr::monotonic_buffer_resource upstream_;
    std::pmr::unsynchronized_pool_resource pool_;
};

// 使用示例
struct MyObject {
    int data;
    MyObject(int d) : data(d) {}
};

int main() {
    ObjectPool pool;
    MyObject* obj1 = pool.allocate<MyObject>(42);
    MyObject* obj2 = pool.allocate<MyObject>(100);
    
    pool.deallocate(obj1);
    // obj1占用的内存会被池化资源复用
    MyObject* obj3 = pool.allocate<MyObject>(200); 

    pool.deallocate(obj2);
    pool.deallocate(obj3);
    return 0;
}
std::pmr是否适合对象池场景?

完全适合。std::pmr的设计初衷就是灵活管理内存分配策略,对象池本质是内存分配的一种复用策略。通过组合不同的memory_resource,你可以轻松实现:

  • 固定缓冲区的内存复用(如上述示例)
  • 多线程安全的对象池(替换为synchronized_pool_resource)
  • 根据对象大小自动调整的池化策略(池化资源会自动管理不同大小的内存块)
实际使用std::pmr的经验
  1. 高并发服务的小对象优化:在我维护的TCP网关服务中,每个请求会创建多个小对象(请求头、数据包片段),原用malloc/free导致频繁系统调用,CPU开销高。换成std::pmr::synchronized_pool_resource配合预分配缓冲区后,小对象分配耗时降低约40%,同时减少了内存碎片。
  2. 嵌入式系统的内存管控:在嵌入式设备中,不能随意动态分配内存。我用monotonic_buffer_resource绑定设备上的固定内存区域,配合pmr容器(pmr::vector、pmr::string),实现了完全无动态内存分配的模块,避免了内存泄漏和碎片问题。
  3. 线程安全的选择:单线程场景一定要用unsynchronized_pool_resource,它比synchronized_pool_resource快很多;多线程场景必须用后者,否则会出现数据竞争。
  4. 避免过度嵌套资源:曾经试过嵌套三层memory_resource(pool -> monotonic -> system),结果分配开销反而比直接用系统资源高,简化为pool直接绑定monotonic后,性能立刻回升。
  5. monotonic_buffer_resource的reset:如果用monotonic作为上游,当不需要再分配新内存时,可调用upstream_.reset()释放所有已分配内存(需确保所有对象已销毁,否则会导致野指针)。

内容的提问来源于stack exchange,提问作者user14542318

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 07:55:26