Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← C++ 编程 / C++ Programming

内存管理 / Memory Management

1. C++ 内存管理总览:先看完整地图 / C++ Memory Management Map

2. 程序内存布局:内存不是只有堆和栈 / Program Memory Layout

3. 栈与函数调用:局部变量为什么会消失 / Stack and Function Calls

4. 堆与动态分配:new 到底做了什么 / Heap and Dynamic Allocation

5. 对象生命周期:地址还在不代表对象还活着 / Object Lifetime

6. RAII 与所有权:让对象负责清理 / RAII and Ownership Design

7. 智能指针与所有权关系:谁拥有,谁只是看 / Smart Pointers and Ownership Graphs

8. 容器、迭代器与内存失效 / Containers, Iterators, and Invalidation

9. allocator 与 PMR:把分配策略抽出来 / Allocators and PMR

10. 内存错误与 Sanitizer:把崩溃变成证据 / Memory Errors and Sanitizers

本页目录

allocator 与 PMR:把分配策略抽出来 / Allocators and PMR ​

这一篇偏高级。

如果你刚学完堆、RAII、智能指针,可以先知道 allocator 解决什么问题,不必立刻在业务代码里使用 PMR。

1. allocator 解决的不是“怎么 new 一个对象” ​

普通代码里,你写:

cpp
std::vector<int> values;
values.push_back(1);
1
2

vector 需要动态存储元素。

默认情况下,它会使用标准分配器。

allocator 的大方向是:

text
容器负责管理元素生命周期和结构。
allocator 负责提供和回收原始存储。
1
2

拆开看:

text
vector wants more capacity
  |
  v
allocator provides raw storage
  |
  v
vector constructs elements there
  |
  v
vector destroys elements when needed
  |
  v
allocator releases raw storage
1
2
3
4
5
6
7
8
9
10
11
12
13

所以 allocator 和对象生命周期相关,但它不等于对象本身。

2. 为什么需要自定义分配策略 ​

默认分配器已经够普通程序使用。

自定义分配策略通常出现在:

text
大量小对象频繁分配释放
希望把一批临时对象放在同一块区域
降低内存碎片
统计分配次数和大小
限制模块只能从某个内存池分配
游戏、交易、嵌入式等对延迟敏感场景
1
2
3
4
5
6

例如解析一个请求时,会产生很多临时字符串和节点。

请求处理完以后,这些临时对象可以一起释放。

这时逐个 new/delete 成本和碎片可能不理想。

3. PMR 是什么 ​

PMR 是 Polymorphic Memory Resource。

可以先理解成:

text
把“从哪里分配内存”变成运行时可替换的资源对象。
1

头文件:

cpp
#include <memory_resource>
1

PMR 容器例子:

cpp
#include <memory_resource>
#include <vector>

int main() {
    std::pmr::vector<int> values;
    values.push_back(1);
}
1
2
3
4
5
6
7

std::pmr::vector<int> 和普通 std::vector<int> 的接口很像。

差别在于它使用 std::pmr::memory_resource 来分配内存。

4. monotonic_buffer_resource ​

一个常见资源是:

cpp
#include <array>
#include <memory_resource>
#include <vector>

int main() {
    std::array<std::byte, 1024> buffer{};
    std::pmr::monotonic_buffer_resource resource(
        buffer.data(),
        buffer.size()
    );

    std::pmr::vector<int> values{&resource};
    values.push_back(1);
    values.push_back(2);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

这里大致是:

text
stack buffer
+--------------------------------+
| 1024 bytes                     |
+--------------------------------+
        ^
        |
monotonic_buffer_resource
        ^
        |
pmr::vector uses this resource
1
2
3
4
5
6
7
8
9
10

monotonic 的意思是分配指针大体向前走。

它通常不逐个回收小块内存。

等资源对象销毁时,再把整体资源释放或结束使用。

这适合“一批临时分配一起结束”的场景。

5. 生命周期陷阱 ​

PMR 最容易出错的不是语法。

而是资源对象的生命周期。

看危险代码:

cpp
#include <array>
#include <memory_resource>
#include <vector>

std::pmr::vector<int> make_values() {
    std::array<std::byte, 1024> buffer{};
    std::pmr::monotonic_buffer_resource resource(
        buffer.data(),
        buffer.size()
    );

    std::pmr::vector<int> values{&resource};
    values.push_back(1);
    values.push_back(2);
    return values;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

问题是:

text
buffer 是局部对象
resource 是局部对象
values 使用 resource 分配元素存储
函数返回后 buffer 和 resource 都没了
返回出去的 values 仍然以为自己有可用资源
1
2
3
4
5

这就是典型生命周期错误。

PMR 不会自动让资源比容器活得更久。

你必须保证:

text
memory_resource 的生命周期
  至少覆盖所有使用它的容器
1
2

6. allocator 和 RAII 的关系 ​

allocator 管的是原始存储策略。

容器仍然负责 RAII:

text
vector 析构
  |
  v
析构元素
  |
  v
通过 allocator/resource 归还存储
1
2
3
4
5
6
7

所以 allocator 不是绕开 RAII。

它是让 RAII 容器使用不同的底层存储来源。

如果这句话现在还抽象,可以先记:

text
不要一上来学 allocator API。
先理解容器什么时候分配、什么时候构造元素、什么时候析构元素。
1
2

7. 什么时候不要用 PMR ​

以下场景一般不需要:

text
普通业务代码
对象数量不大
没有明确性能瓶颈
团队不熟悉资源生命周期约束
代码可读性比微优化更重要
1
2
3
4
5

PMR 是工具,不是现代 C++ 的必备仪式。

如果只是想避免手写 new/delete,应该先用:

text
std::vector
std::string
std::unique_ptr
std::shared_ptr
1
2
3
4

不是先上 allocator。

8. 本篇总结 ​

allocator/PMR 的位置是:

text
container
  管理元素、size、capacity、构造析构

allocator / memory_resource
  管理原始存储从哪里来、怎么归还
1
2
3
4
5

最重要的判断是:

text
这个分配策略真的解决了当前问题吗?
memory_resource 是否比使用它的容器活得更久?
出了问题时,团队能不能读懂这层抽象?
1
2
3

学到这里,你不需要马上写自定义 allocator。

但你应该能看懂:allocator 是把“内存从哪里来”从容器逻辑中抽出来。

最后更新于:

Pager
上一篇8. 容器、迭代器与内存失效 / Containers, Iterators, and Invalidation
下一篇10. 内存错误与 Sanitizer:把崩溃变成证据 / Memory Errors and Sanitizers

持续记录,持续成长

Copyright © Tidenflow