Advanced 26 min readModule: Module 15: Memory Management: Custom PMR & Arena Allocators
Polymorphic Memory Resources (std::pmr) & Arenas
Eliminate heap allocation latency with C++17/20 Polymorphic Memory Resources (`std::pmr`): monotonic buffer arenas, stack-based `monotonic_buffer_resource`, pool resources, and custom allocation strategies.
What You Will Learn in This Lesson
- Why standard `std::allocator` embeds the allocator type into the container's type signature
- How `std::pmr` uses dynamic polymorphism to change allocation strategies without changing container types
- Zero-heap stack allocation using `std::pmr::monotonic_buffer_resource`
- Eliminating memory fragmentation using `std::pmr::unsynchronized_pool_resource`
Introduction & Core Concept
In standard C++ (C++11/14), the allocator was part of the container's type: `std::vector<int, MyAlloc>` and `std::vector<int, OtherAlloc>` were incompatible types that could not be passed into the same function. C++17 introduced Polymorphic Memory Resources (`std::pmr`), allowing containers (`std::pmr::vector`, `std::pmr::string`) to share identical types while swapping underlying memory resources at runtime.
WHY DOES THIS MATTER IN THE REAL WORLD?
Calling `malloc` or `new` inside high-frequency loops incurs lock contention and system call overhead. A Monotonic Buffer Arena allocates from a pre-allocated stack buffer in a single CPU pointer increment (O(1)), boosting performance by 10x-50x.
Syntax & Structure
cpp
char stack_buf[1024];std::pmr::monotonic_buffer_resource mem_res(stack_buf, sizeof(stack_buf));std::pmr::vector<int> vec(&mem_res);Zero-Heap Vector Allocations with std::pmr Monotonic Arena
cppcpp
1234567891011121314151617181920212223242526272829303132333435// C++17/20 Polymorphic Memory Resources (std::pmr) Demonstration#include <iostream>#include <vector>#include <string>#include <memory_resource>#include <chrono>int main() {std::cout << "=== Polymorphic Memory Resources (std::pmr) Arena ===" << std::endl;// 1. Pre-allocate a 64KB Stack Buffer (Zero Heap Allocation!)alignas(std::max_align_t) char stack_arena[64 * 1024];// 2. Initialize Monotonic Buffer Resource// Memory allocations simply advance a pointer (O(1) nanosecond allocation)std::pmr::monotonic_buffer_resource arena_resource(stack_arena, sizeof(stack_arena),std::pmr::null_memory_resource() // Disallow heap fallbacks);// 3. Create PMR containers using the stack arenastd::pmr::vector<std::pmr::string> course_catalog(&arena_resource);course_catalog.emplace_back("C++20 Coroutines Architecture");course_catalog.emplace_back("Lock-Free Ring Buffers");course_catalog.emplace_back("Polymorphic Memory Resources (PMR)");for (const auto& item : course_catalog) {std::cout << "PMR Item: " << item << " (Allocated in stack arena)" << std::endl;}std::cout << "✅ All vector elements and strings allocated in stack arena with ZERO heap calls!" << std::endl;// When arena_resource goes out of scope, ALL memory is reclaimed at once in 0ms!return 0;}
Line-by-Line Technical Breakdown
1PMR Pool Resources: For long-running servers with varying object lifetimes, `std::pmr::unsynchronized_pool_resource` organizes allocations into fixed-size geometric chunk pools (bins), completely eliminating memory fragmentation and heap lock contention.
Try It Yourself (Interactive Editor)
Modify the code in real-time and click Run to test live browser output and console logs.
Intelligent Code Runner & Live Sandbox[CPP]
CPP SOURCE EDITOR
Interactive Live CodeCommon Mistakes & How to Avoid Them
#1: Passing a temporary `std::pmr` container to a context that outlives the container's backing `memory_resource`.
Containers store a raw pointer to their `memory_resource`. If the resource is destroyed first, accessing container elements causes a Use-After-Free crash.
Incorrect / Antipattern
std::pmr::vector<int> create() { char buf[100]; std::pmr::monotonic_buffer_resource res(buf, 100); return std::pmr::vector<int>(&res); }Correct / Professional Solution
// Ensure the memory resource outlives all containers that reference itIndustry Best Practices & Professional Standards
- Use `std::pmr::monotonic_buffer_resource` for per-request / per-frame scratchpad allocations.
- Use `std::pmr::null_memory_resource()` as an upstream fallback to strictly enforce zero-heap allocation budgets.
- Use `std::pmr::synchronized_pool_resource` for multi-threaded object pools.
Lesson Summary & Core Takeaways
- `std::pmr` decouples container types from their underlying memory allocation strategy.
- Monotonic Arenas provide nanosecond O(1) pointer-bump allocation.
- Bulk arena deallocation eliminates individual object destruction overhead.