65 lines
2.9 KiB
Markdown
65 lines
2.9 KiB
Markdown
# Paged Memory Arena Architecture
|
|
|
|
## Status
|
|
**Implemented & Active** (Jan 2026)
|
|
|
|
## Overview
|
|
The memory system uses a **Paged Arena** model backed by global **Memory Pools**. This architecture supports indefinite growth, efficient clearing, and minimizes OS-level allocations by sub-allocating from large pre-reserved buffers.
|
|
|
|
## Architecture
|
|
|
|
### 1. Memory Pool (`MemoryPool`)
|
|
A Global Source of memory blocks.
|
|
- **Role**: Manages a large contiguous memory region (e.g., 512MB for Game).
|
|
- **Implementation**: Free List Allocator.
|
|
- **Operations**: `AllocateBlock` (First-Fit with Splitting), `FreeBlock` (Returns to list).
|
|
- **Optimization**: **Block Splitting** is implemented to preserve free space. If a block in the free list is significantly larger than requested (`Alloc + Header + 16 bytes`), it is split, and the remainder is returned to the free list. This prevents pool exhaustion from small allocations consuming large blocks.
|
|
- **Instances**:
|
|
- `g_EngineMemory` (256MB)
|
|
- `g_GameMemory` (512MB)
|
|
- `g_ScratchMemory` (64MB)
|
|
|
|
### 2. Memory Arena (`MemoryArena`)
|
|
A High-Level Allocator.
|
|
- **Structure**: A linked list of `MemoryBlocks`.
|
|
- **Behavior**:
|
|
- **Growth**: Starts with one block. If an allocation exceeds capacity, it requests a new Block (Page) from the backing Pool and links it.
|
|
- **Alloc**: Linear bump-pointer within the current block.
|
|
- **Clear**: Returns all blocks (except the first) to the Pool. Resets the first block.
|
|
- **Realloc**: Supports in-place expansion (if top of stack) or copy-and-move.
|
|
- **Instances**: `GetGameArena()`, `GetEngineArena()`, `GetScratchArena()`.
|
|
|
|
### 3. Memory Block (`MemoryBlock`)
|
|
The unit of exchange between Pool and Arena.
|
|
- **Header**: Includes `Magic` (debug safety), `Next` pointer, `TotalSize` (renamed from `Size`), and `Used` offset.
|
|
- **Alignment**: 16-byte alignment enforced.
|
|
- **Safety**: Debug builds use memory poisoning (`0xCD` on alloc, `0xDD` on free) and Magic number checks to detect corruption.
|
|
|
|
### 4. Arena Pop (`ArenaPop`)
|
|
Support for LIFO allocations (reclaiming memory).
|
|
- **Behavior**: Checks if the pointer is at the very top of the stack (`CurrentBlock->Used`).
|
|
- **Optimization**: If valid, decrements `Used` to reclaim space. If not (fragmented), does nothing.
|
|
- **Usage**: Critical for `ImGui` vector resizing to prevent exponential memory consumption.
|
|
|
|
## Usage
|
|
|
|
```cpp
|
|
// 1. Get an Arena
|
|
MemoryArena* arena = GetScratchArena();
|
|
|
|
// 2. Push Data
|
|
MyStruct* data = ArenaPushType<MyStruct>(arena, "Tag");
|
|
void* raw = ArenaPush(arena, 1024, 16, "RawBuffer");
|
|
|
|
// 3. Pop Data (LIFO)
|
|
ArenaPop(arena, raw, 1024); // Reclaims memory
|
|
|
|
// 4. Reset (Scratch only)
|
|
ScratchArenaReset(); // Returns pages to g_ScratchMemory
|
|
```
|
|
|
|
## Migration Status
|
|
- **ImGui**: Migrated to `GetEngineArena()` (Paged) with `ArenaPop` support for efficient vector resizing.
|
|
- **Display/Window**: Uses Engine Arena.
|
|
- **Game Entities**: Uses Game Arena.
|