Upgraded MemoryArena to allow poping memory and creating an arena for a specific part and not pushing completely on the same stack.

Made with Gemini
+ Updates skills to have better agents.
This commit is contained in:
2026-01-25 11:01:32 -05:00
parent 73db1174f2
commit 0788fdeb98
11 changed files with 508 additions and 266 deletions

View File

@@ -1,45 +1,64 @@
# Memory System Status & Migration Plan
# Paged Memory Arena Architecture
## Completed Work
## Status
**Implemented & Active** (Jan 2026)
### Core Systems
- **MemoryArena**: Implemented linear allocator with alignment, markers, and reset support.
- **Global Arenas**:
- `ScratchArena` (64MB): Transient per-frame memory.
- `EngineArena` (256MB): Persistent engine memory (internal).
- `GameArena` (512MB): Persistent game memory (exported to Game DLL).
- **Helpers**: Added `ArenaPushType<T>` and `ArenaPushArray<T>` with automatic zero-initialization.
## 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.
### Migrated Subsystems
- **Display**: `Win32Window` and `Win32DisplayDevice` now use `EngineArena`.
- **Game Entities**: `Entity.h` uses `GameArena` for entity allocation; manual `free` calls removed from `game.cpp`.
- **Hot Reload**: `HotReload.cpp` (persistent paths to `EngineArena`) and `Win32HotReload.cpp` (temp paths to `ScratchArena`).
## Architecture
## Remaining Work
### 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)
The following subsystems still use legacy `malloc`/`calloc`/`realloc`/`free` and need to be migrated.
### 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.
### IO System
- **Files**: `Core/HAL/IO/IOStream.cpp`, `Core/HAL/IO/Win32/Win32IOStream.cpp`
- **Allocations**: `IOStream` instance, data buffers, `Win32IOStreamDataPayload`.
- **Challenge**: `Realloc` is used for growing buffers.
- **Strategy**:
- `IOStream` struct -> `ScratchArena` (if transient) or `EngineArena`.
- Buffers: Evaluate if `ArenaPush` with large enough capacity is sufficient, or implement a growable buffer on top of arena (or use `std::vector` with custom allocator if absolutely needed, but prefer simple fixed max size if possible).
## Usage
### Graphics / Debug
- **Files**: `Graphics/DebugDisplayRenderer.cpp`
- **Allocations**: `DepthTestedVertices`, `OverlayVertices`.
- **Strategy**: Use `EngineArena` or a dedicated `RenderArena` if these are persistent. If per-frame, move to `ScratchArena`.
```cpp
// 1. Get an Arena
MemoryArena* arena = GetScratchArena();
### Shader Compiler
- **Files**: `JulietShaderCompiler/ShaderCompiler.cpp`
- **Allocations**: Argument arrays, file buffers.
- **Strategy**: Use `ScratchArena` for all compilation tasks as they are transient.
// 2. Push Data
MyStruct* data = ArenaPushType<MyStruct>(arena, "Tag");
void* raw = ArenaPush(arena, 1024, 16, "RawBuffer");
### Filesystem
- **Files**: `Core/HAL/Filesystem/Filesystem.cpp`
- **Allocations**: `CachedBasePath`.
- **Strategy**: Migrate to `EngineArena` (persistent).
// 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.