C++17 Polymorphic Memory Resource (pmr)
std::pmr(Polymorphic Memory Resource)은 C++17에서 도입된 런타임 교체 가능한 메모리 할당 추상화입니다. 컨테이너의 할당자(Allocator)를 컴파일 타임이 아닌 런타임에 결정할 수 있어 스택 버퍼, 풀, 모노토닉 할당자 등을 유연하게 적용할 수 있습니다.
1. pmr 컨테이너 기본
섹션 제목: “1. pmr 컨테이너 기본”#include <memory_resource>#include <vector>#include <string>
int main(){ // 스택 버퍼를 메모리 소스로 사용 std::array<std::byte, 1024> buf; std::pmr::monotonic_buffer_resource pool(buf.data(), buf.size());
// 힙 할당 없이 스택 버퍼에서 할당 std::pmr::vector<int> v(&pool); v.push_back(1); v.push_back(2); v.push_back(3);
std::pmr::string s(&pool); s = "hello world";}// 풀 소멸 시 모든 메모리 일괄 해제2. monotonic_buffer_resource
섹션 제목: “2. monotonic_buffer_resource”한 방향으로만 늘어나며 해제가 없는 가장 빠른 할당자입니다.
#include <memory_resource>
void process_frame(){ // 프레임당 128KB 스택 버퍼 std::array<std::byte, 128 * 1024> frame_buf; std::pmr::monotonic_buffer_resource arena( frame_buf.data(), frame_buf.size(), std::pmr::null_memory_resource()); // 오버플로 시 throw
std::pmr::vector<std::pmr::string> results(&arena);
for (int i = 0; i < 100; ++i) results.emplace_back(std::to_string(i), &arena);
// 프레임 끝: arena 소멸 → 일괄 해제 (O(1))}3. synchronized_pool_resource
섹션 제목: “3. synchronized_pool_resource”고정 크기 블록 풀로 단편화 없이 할당/해제를 반복합니다.
#include <memory_resource>
std::pmr::synchronized_pool_resource pool( std::pmr::pool_options{ .max_blocks_per_chunk = 20, .largest_required_pool_block = 1024 });
// 여러 스레드에서 안전하게 사용 가능std::pmr::vector<int> v1(&pool);std::pmr::vector<int> v2(&pool);unsynchronized_pool_resource는 단일 스레드 전용이지만 더 빠릅니다.
4. 커스텀 memory_resource
섹션 제목: “4. 커스텀 memory_resource”#include <memory_resource>#include <cstdlib>#include <iostream>
class LoggingResource : public std::pmr::memory_resource{ std::pmr::memory_resource* upstream_; std::size_t allocated_ = 0;
protected: void* do_allocate(std::size_t bytes, std::size_t align) override { allocated_ += bytes; std::cout << "[alloc] " << bytes << " bytes (total: " << allocated_ << ")\n"; return upstream_->allocate(bytes, align); }
void do_deallocate(void* p, std::size_t bytes, std::size_t align) override { allocated_ -= bytes; std::cout << "[free] " << bytes << " bytes (total: " << allocated_ << ")\n"; upstream_->deallocate(p, bytes, align); }
bool do_is_equal(const memory_resource& o) const noexcept override { return this == &o; }
public: explicit LoggingResource(std::pmr::memory_resource* up = std::pmr::get_default_resource()) : upstream_(up) {}
std::size_t total_allocated() const { return allocated_; }};
int main(){ LoggingResource logger; std::pmr::vector<std::pmr::string> v(&logger); v.emplace_back("hello", &logger); v.emplace_back("world", &logger);}5. 표준 제공 resource
섹션 제목: “5. 표준 제공 resource”| 리소스 | 특성 |
|---|---|
monotonic_buffer_resource | 단방향 할당, O(1) 해제, 가장 빠름 |
unsynchronized_pool_resource | 블록 풀, 단일 스레드 |
synchronized_pool_resource | 블록 풀, 멀티 스레드 안전 |
new_delete_resource() | 전역 new/delete 위임 |
null_memory_resource() | 항상 throw (오버플로 감지) |
6. 체인 구성
섹션 제목: “6. 체인 구성”// 버퍼 → 풀 → 글로벌 힙 체인std::array<std::byte, 4096> buf;std::pmr::monotonic_buffer_resource mono( buf.data(), buf.size(), std::pmr::new_delete_resource()); // 버퍼 고갈 시 힙으로 폴백
std::pmr::unsynchronized_pool_resource pool(&mono);
std::pmr::vector<int> v(&pool);std::pmr은 컨테이너를 바꾸지 않고 메모리 전략만 교체하는 Zero-overhead 추상화입니다. 프레임 단위 임시 할당에는 monotonic_buffer_resource, 빈번한 할당/해제 사이클에는 pool_resource를 사용하세요. 커스텀 memory_resource로 진단, 추적, 한도 제한 등 프로젝트 특화 할당 정책을 구현할 수 있습니다.