为什么自定义 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 而是堆碎片 —— 长时间运行的服务差异巨大。