Memory

Purpose

Memory provides CPU block bookkeeping, pooled object construction, reservations and retained release contexts. Storage ownership and an object’s live state are separate; returning a block is not permission to destroy still-live objects.

Interface

Types below are in CE::Memory unless another namespace is shown.

For ordinary application objects, start with Objects::Pool<T> and its retained handles. Use reservations for explicitly selected construction, and read the allocator requirements when implementing storage integration rather than using the default pool.

Types and operations

API and purpose

Block, Manager
Describe ranges and check out/return/coalesce CPU storage. Pool ownership; block transactions.

Objects::Pool
Construct retained object handles whose release state can outlive the facade. Object-pool ownership.

Objects::Reservation
Reserve slots and transfer individually constructed objects into handles. Reservation and allocator requirements.

Objects::Constructor
Track construction phases while user constructors/destructors run outside bookkeeping locks. Object construction.

ByteReleaseContext
Retain byte bookkeeping for final release without a destroyed-manager lookup. Release contexts.

Storage and lifetime choices

Choice

Purpose and details

Pooled handles / reserved slots

Handles own claimed objects; a reservation returns only its unclaimed ranges. Reservation lifetime.

Allocators::ObjectPoolAllocator

Supplies the retained manager/release contract needed by reservations; ordinary allocators do not automatically qualify. Supported allocators.

FitPolicy

exact, larger, greedy select length-growth policy; these helpers do not allocate storage. Fit arithmetic and limits.

CPU / native resource ownership

CPU bookkeeping does not authorize native GPU use or replace graphics retirement. CPU lifetime; native retirement.

Usage

Start with Memory::Objects::Pool when application objects should be constructed now and released independently. The returned handles retain their release state; owning a handle does not synchronize the object’s members.

        ---
config:
  theme: base
  themeVariables:
    fontFamily: system-ui, sans-serif
    fontSize: 14px
  flowchart:
    htmlLabels: true
    curve: linear
    nodeSpacing: 22
    rankSpacing: 38
    padding: 12
---
flowchart TB
    accTitle: Memory · application object storage
    accDescr: Local names omit Memory::; ambiguous nested namespaces remain qualified. Arrows point toward the API or type used, not call order or data flow. Methods beneath type names are selected application entry points; Implement hooks marks engine-invoked overrides. Dashed arrows mark optional choices.
    k0(["Application<br/>storage owner"]):::app
    k1["<b>Objects::<br/>Pool</b><br/><br/>get(): Objects::Pool&lt;T&gt;<br/><br/>retrieve_objects(N, args...): T[]<br/><br/>cull(age)<br/><br/>release_culled()"]:::focal
    k2["<b>Objects::<br/>Reservation</b><br/><br/>Reservation(count, Allocator)<br/><br/>emplace(index, args...): T<br/><br/>remaining_ranges(): Block&lt;T&gt;[]"]:::focal
    k3(["Application<br/>object type"]):::app
    k4(["Application-owned game objects"]):::app
    k5(["Application<br/>cleanup / quiesce()"]):::app
    k0 --> k1
    k0 -.-> k2
    k2 --> k3
    k4 --> k3
    k5 -.-> k1
    k1 --> k3
    classDef focal fill:#e7f3ef,stroke:#387d6b,color:#153d33,stroke-width:1.2px
    classDef neighbor fill:#f0f3f8,stroke:#8c9bb1,color:#35445b,stroke-width:1px
    classDef app fill:#fff2df,stroke:#c09452,color:#674515,stroke-dasharray:5 3
    classDef system fill:#eaf0fc,stroke:#617fab,color:#263f69,stroke-width:1.2px
    linkStyle default stroke:#7e8fa7,stroke-width:1.2px

    

Local names omit Memory:: where unambiguous. Explore this diagram and its other views →

The engine dependency view follows caches and geometry into their actual storage owners.

Choose storage and construction together

Need

Entry point

What the caller retains

Construct every object in a batch now

Memory::Objects::Pool<T>::retrieve_objects()

One shared handle per live object; its final release destroys and returns that slot.

Construct selected slots with different arguments

Memory::Objects::Reservation

The reservation owns unclaimed slots; claimed handles can outlive it. A failed constructor leaves its slot available to retry.

Integrate an ordinary allocator for a complete batch

Memory::Objects::Factory

Element handles release independently; the last handle releases the original whole allocation.

Manage bytes or build a storage adapter

Memory::Manager and Memory::ByteReleaseContext

A live facade for acquisition and a captured release context for final returns. Object construction remains a separate responsibility.

An allocator that supports whole-allocation allocate/deallocate is not necessarily valid for reservations. The default Memory::Allocators::ObjectPoolAllocator supplies retained release state and interior-range return. See the allocation recipes and allocator requirements.

Uses

Consumer

Dependency

Relationship

Memory::Objects::Pool<T>

Memory::Objects::PoolState

Retains the release operations that object handles capture instead of looking up the pool during deletion.

Memory::Objects::PoolState<T>

Memory::Objects::Constructor

Retains construction tracking for pooled object lifetime; user constructors/destructors run outside tracking locks.

Memory::Objects::Reservation<T>

Memory::Allocators::ObjectPoolAllocator<T> and Memory::Block

Tracks only unclaimed ranges and transfers individual slots into handles.

Memory::Manager and Memory::Objects::Pool<T>

State::Singleton

Offer shared facade access. Retained handles do not depend on a later singleton lookup. State.

Memory::Manager

Memory::FitPolicy and address/fit helpers

Computes request growth/alignment before bookkeeping checkout. Utilities.

Byte bookkeeping

Memory::Stats and Diagnostics::DomainId

Copies synchronized allocation observations before formatting or reporting. Diagnostics.

Used by

Consumer

Memory entry point

Why it is used

Application object owners

Memory::Objects::Pool<T> or Memory::Objects::Reservation<T>

Retain independently released CPU objects without starting a runtime service.

Assets::Cache::Store

Memory::Objects::Reservation<T> / Memory::Allocators::ObjectPoolAllocator<T>

Reserves cache object storage and creates handles only for constructed entries. Assets.

Assets::Grids::GeometryData preparation

Memory::ExactManager and retained byte release

Holds CPU vertex backing produced by Assets::Grids::make_geometry(). Grid geometry.

Text::Legacy::AsciiFontData preparation

Memory::ExactManager and retained byte release

Supplies CPU glyph vertices while building/uploading the legacy font. Text.

CPU release and native retirement

Returning CPU storage and retiring a graphics resource have different owners. Release live objects before returning their raw ranges. For GPU-backed assets, dropping a CPU handle does not authorize a native deletion call: the resource owner collects native retirement on the appropriate backend thread/context.

Contracts

Checkout/return preserves nonoverlapping ownership and contiguous partition invariants. Construct/destroy operations on a busy slot reject. User constructors and destructors run outside tracking locks. Allocation or batch construction may fail after earlier independent work succeeds; owners must clean up completed objects. Trusted destructor release is nonthrowing and terminates on broken bookkeeping invariants.

Block/pointer helpers do not validate every dereference or establish C++ object lifetime. Callers remain responsible for live object access, alignment and external quiescence where raw collection access is used.

Lifecycle

Acquire storage with a live manager, construct objects, retain handles and let their deleters destroy/return slots through captured release state. That state can outlive the facade. A reservation returns unclaimed ranges; claimed handles may survive it. Finish facade callers before destroying the facade even when retained contexts permit later final release.

Execution

Bookkeeping and distinct-slot construction support synchronized/reentrant operations as documented. This does not synchronize members of a pooled game object. Choose a simulation owner or add application synchronization. Native GPU release continues to follow backend affinity/retirement rather than these CPU manager locks.

Integration

A class can allocate a batch of default-constructible application particles:

struct Particle { float age = 0; };
auto particles = CE::Memory::Objects::Pool<Particle>::get().retrieve_objects(16);
particles.front()->age = 0.25f;
particles.clear();

Each shared handle retains the release context. Keep mutation on the game’s owner; sharing a handle alone does not make age synchronized.

Limits and further reading

There is no general memory budget, automatic world ownership or NUMA placement policy here. Read CPU memory lifetime and reservation, value/pointer utility contracts, object pool declarations and native resource lifetime.