输入关键词开始搜索

C++ Allocator — 自定义内存分配

为什么自定义 Allocator

// std::vector 默认用 new/delete 分配 → 频繁小块分配 → 堆碎片
std::vector<int> v;
for (int i = 0; i < 1000000; ++i) v.push_back(i);  // 多次 realloc

// 自定义 allocator → 预分配一大块 → 零碎片

pmr (Polymorphic Memory Resource) — C++17

#include <memory_resource>

// monotonic_buffer — 只增长不释放(最快,适合短期大量分配)
char buffer[1024 * 1024];  // 1MB 栈上缓冲区
std::pmr::monotonic_buffer_resource pool{buffer, sizeof(buffer)};

std::pmr::vector<int> v{&pool};  // 用自定义分配器的 vector
for (int i = 0; i < 100000; ++i) v.push_back(i);
// 所有分配走 buffer,无堆碎片,构造完成后一次性释放

三种 pmr 分配器

类型特点场景
monotonic_buffer_resource只分配不释放,析构时全部回收请求生命周期内的临时数据
unsynchronized_pool_resource内存池,线程不安全但快单线程高频分配
synchronized_pool_resource线程安全内存池多线程
// 内存池 + 后备分配器
std::pmr::unsynchronized_pool_resource pool;

std::pmr::vector<int> hotPath{&pool};   // 高频路径走池
std::pmr::vector<int> coldPath;          // 低频路径走默认 new

hotPath.reserve(1000);                   // 池预分配

自定义 Allocator(兼容旧 STL)

template <typename T>
class Mallocator {
public:
    using value_type = T;
    Mallocator() = default;
    template <typename U> Mallocator(const Mallocator<U> &) {}

    T *allocate(size_t n) {
        if (n > max_size()) throw std::bad_alloc();
        void *p = malloc(n * sizeof(T));  // 自己控制分配方式
        if (!p) throw std::bad_alloc();
        return static_cast<T *>(p);
    }
    void deallocate(T *p, size_t) { free(p); }
    size_t max_size() const { return SIZE_MAX / sizeof(T); }
};

// 使用
std::vector<int, Mallocator<int>> v;

性能对比

场景: 100 万次 int push_back

默认 std::allocator:      8 次 realloc, ~20ms
monotonic_buffer(栈上):    0 次 realloc, ~8ms  ← 无碎片
unsynchronized_pool:       0 次 realloc, ~10ms

省下的不是 CPU 而是堆碎片 —— 长时间运行的服务差异巨大。