TL;DR

  1. C++17 以后 PMR 值得看,因为数据库系统会产生很多短生命周期小对象。
  2. PMR 和 smart pointer 解决的问题不同。smart pointer 描述 ownership;PMR 描述 allocation locality 和 lifetime grouping。
  3. 重要边界:我没有在检查的 DuckDB snapshot 里看到大量 PMR 使用。这里讨论的是设计方向,不是当前实现事实。

PMR 问的问题

PMR 是 std::pmr,全称 polymorphic memory resource。它是 C++17 的标准库特性。

它主要问的不是:

谁拥有这个对象?

这个问题 smart pointer 已经能回答。

PMR 问的是:

很多小对象、很多 container、生命周期差不多。
它们应该从哪里分配内存?

这个问题在数据库系统里很自然。

这种模式在哪里出现

数据库系统经常构造短生命周期结构:

  • binder 里的临时 expression list
  • optimizer 里的 join graph
  • rule rewrite 的中间节点
  • candidate plan/path
  • query-local metadata
  • debug/report structure

这些对象通常会在一个 query 或 optimizer phase 结束时一起死亡。

用普通 std::vector、std::unordered_map、std::string 时,每个 container 都走默认 allocator。小分配多了以后,内存会更分散,也更难统计。

PMR 可以让这些 container 共用一个 memory resource:

std::pmr::monotonic_buffer_resource arena;

std::pmr::vector<Node *> nodes{&arena};
std::pmr::unordered_map<int, Cost> costs{&arena};
std::pmr::string label{&arena};

这有点像 PostgreSQL MemoryContext 的 C++ 版本,但它和 STL container 结合得更自然。

PMR vs smart pointer

Smart pointer 描述 ownership:

谁负责销毁这个对象?

PMR 描述 allocation grouping:

这些对象属于同一个 query。
这些对象属于同一个 optimizer phase。
这些对象可以一起释放。

两者解决的是不同问题:

问题更合适的工具
单个对象所有权unique_ptr
资源自动释放RAII
一组短生命周期小对象PMR
PostgreSQL C 代码里的区域生命周期MemoryContext

不要到处都用

PMR 不能机械使用。

DuckDB 已经有自己的 execution memory layout:Vector、DataChunk、validity mask、selection vector、string heap、buffer manager state、hash table payload。这些都靠近 hot path。

PMR 在这些地方是否有帮助,要看代码生成、cache locality、memory accounting 和现有 memory manager。

更合理的起点是:

先用于 parser、binder、optimizer、debug structure。
谨慎进入 execution hot path。
不要绕过已有 memory manager 或 buffer manager。

PMR 有价值,是因为它匹配数据库里的生命周期模式,而不是因为它是现代 C++。