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 |
|---|
|
|
|
|
|
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. |
Supplies the retained manager/release contract needed by reservations; ordinary allocators do not automatically qualify. Supported allocators. |
|
|
|
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<T><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<T>[]"]:::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 |
One shared handle per live object; its final release destroys and returns that slot. |
|
Construct selected slots with different arguments |
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 |
Element handles release independently; the last handle releases the original whole allocation. |
|
Manage bytes or build a storage adapter |
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 |
|---|---|---|
Retains the release operations that object handles capture instead of looking up the pool during deletion. |
||
Retains construction tracking for pooled object lifetime; user constructors/destructors run outside tracking locks. |
||
|
Tracks only unclaimed ranges and transfers individual slots into handles. |
|
Offer shared facade access. Retained handles do not depend on a later singleton lookup. State. |
||
|
Computes request growth/alignment before bookkeeping checkout. Utilities. |
|
Byte bookkeeping |
Copies synchronized allocation observations before formatting or reporting. Diagnostics. |
Used by
Consumer |
Memory entry point |
Why it is used |
|---|---|---|
Application object owners |
Retain independently released CPU objects without starting a runtime service. |
|
|
Reserves cache object storage and creates handles only for constructed entries. Assets. |
|
|
|
Holds CPU vertex backing produced by |
|
|
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.