MemoryArena updates using Gemini. Add some debug tag so we can debug memory allocations

This commit is contained in:
2026-01-20 22:16:04 -05:00
parent d2b91c46d4
commit 0687ce5af1
2 changed files with 78 additions and 13 deletions

View File

@@ -12,11 +12,27 @@ namespace Juliet
uint8* Data;
size_t Size;
size_t Offset;
#if JULIET_DEBUG
struct AllocationInfo
{
size_t Offset;
size_t Size;
const char* Tag;
};
// Use a simple array for now to avoid std::vector dependency in the header or complex management
// Ideally this should be a linked list or similar
static constexpr size_t kMaxAllocations = 4096;
AllocationInfo Allocations[kMaxAllocations];
size_t AllocationCount = 0;
#endif
};
JULIET_API void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size);
JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment = 16);
JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment = 16);
JULIET_API void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment = 16, const char* tag = nullptr);
JULIET_API void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment = 16, const char* tag = nullptr);
JULIET_API void ArenaReset(MemoryArena* arena);
JULIET_API size_t ArenaGetMarker(MemoryArena* arena);
JULIET_API void ArenaResetToMarker(MemoryArena* arena, size_t marker);
@@ -39,9 +55,10 @@ namespace Juliet
void MemoryArenasShutdown();
template <typename T>
inline T* ArenaPushType(MemoryArena* arena)
inline T* ArenaPushType(MemoryArena* arena, const char* tag = nullptr)
{
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T), alignof(T)));
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T), alignof(T), tag));
if (result)
{
MemSet(result, 0, sizeof(T));
@@ -50,9 +67,10 @@ namespace Juliet
}
template <typename T>
inline T* ArenaPushArray(MemoryArena* arena, size_t count)
inline T* ArenaPushArray(MemoryArena* arena, size_t count, const char* tag = nullptr)
{
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T) * count, alignof(T)));
T* result = static_cast<T*>(ArenaPush(arena, sizeof(T) * count, alignof(T), tag));
if (result)
{
MemSet(result, 0, sizeof(T) * count);

View File

@@ -6,6 +6,11 @@
namespace Juliet
{
namespace UnitTest
{
extern void TestMemoryArena();
}
void MemoryArenaCreate(MemoryArena* arena, void* backingMemory, size_t size)
{
Assert(arena);
@@ -13,10 +18,14 @@ namespace Juliet
arena->Data = static_cast<uint8*>(backingMemory);
arena->Size = size;
arena->Offset = 0;
#if JULIET_DEBUG
arena->AllocationCount = 0;
#endif
}
void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment)
void* ArenaPush(MemoryArena* arena, size_t size, size_t alignment, const char* tag)
{
(void)tag; // TODO: Use tag for allocation tracking in Debug builds
Assert(arena);
// Alignment must be power of 2
@@ -35,10 +44,19 @@ namespace Juliet
void* result = arena->Data + (offset - reinterpret_cast<size_t>(arena->Data));
arena->Offset = newOffset;
#if JULIET_DEBUG
if (arena->AllocationCount < MemoryArena::kMaxAllocations)
{
arena->Allocations[arena->AllocationCount] = { offset - reinterpret_cast<size_t>(arena->Data), size, tag ? tag : "Unknown" };
arena->AllocationCount++;
}
#endif
return result;
}
void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment)
void* ArenaRealloc(MemoryArena* arena, void* oldPtr, size_t oldSize, size_t newSize, size_t alignment, const char* tag)
{
Assert(arena);
// Alignment must be power of 2
@@ -46,7 +64,7 @@ namespace Juliet
if (oldPtr == nullptr)
{
return ArenaPush(arena, newSize, alignment);
return ArenaPush(arena, newSize, alignment, tag);
}
if (newSize == 0)
@@ -65,13 +83,13 @@ namespace Juliet
{
// It is the last allocation! We can reuse the space.
// We just need to check if we can expand it (if growing)
// Re-calculate the offset start for this block (to ensure nothing weird with padding)
// Ideally oldPtr was aligned.
// Current Offset corresponds to oldPtrBytes + oldSize.
// We want to move Offset to oldPtrBytes + newSize.
size_t oldPtrOffset = static_cast<size_t>(oldPtrBytes - arena->Data);
size_t newOffset = oldPtrOffset + newSize;
@@ -84,12 +102,20 @@ namespace Juliet
{
// In-place Resize success
arena->Offset = newOffset;
#if JULIET_DEBUG
// Update the last allocation size
if (arena->AllocationCount > 0)
{
arena->Allocations[arena->AllocationCount - 1].Size = newSize;
}
#endif
return oldPtr;
}
}
// Fallback: Alloc + Copy
void* newPtr = ArenaPush(arena, newSize, alignment);
void* newPtr = ArenaPush(arena, newSize, alignment, tag);
if (newPtr)
{
size_t copySize = oldSize < newSize ? oldSize : newSize;
@@ -102,6 +128,9 @@ namespace Juliet
{
Assert(arena);
arena->Offset = 0;
#if JULIET_DEBUG
arena->AllocationCount = 0;
#endif
}
size_t ArenaGetMarker(MemoryArena* arena)
@@ -115,6 +144,20 @@ namespace Juliet
Assert(arena);
Assert(marker <= arena->Offset);
arena->Offset = marker;
#if JULIET_DEBUG
while (arena->AllocationCount > 0)
{
if (arena->Allocations[arena->AllocationCount - 1].Offset >= marker)
{
arena->AllocationCount--;
}
else
{
break;
}
}
#endif
}
// --- Global Arenas & Management ---
@@ -167,6 +210,10 @@ namespace Juliet
MemoryArenaCreate(&g_ScratchArena, g_ScratchBacking, kScratchSize);
MemoryArenaCreate(&g_EngineArena, g_EngineBacking, kEngineSize);
MemoryArenaCreate(&g_GameArena, g_GameBacking, kGameSize);
#if JULIET_DEBUG
UnitTest::TestMemoryArena();
#endif
}
void MemoryArenasShutdown()