Add new Arena Allocator for optimized dynamic memory allocations with a shared lifetime

This commit is contained in:
Wojtek Figat
2025-05-24 05:08:32 +02:00
parent bb855e2663
commit f9cb4ddae2
2 changed files with 99 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#include "ArenaAllocation.h"
#include "../Math/Math.h"
void ArenaAllocator::Free()
{
// Free all pages
Page* page = _first;
while (page)
{
Allocator::Free(page->Memory);
Page* next = page->Next;
Allocator::Free(page);
page = next;
}
}
void* ArenaAllocator::Allocate(uint64 size, uint64 alignment)
{
// Find the first page that has some space left
Page* page = _first;
while (page && page->Offset + size + alignment > page->Size)
page = page->Next;
// Create a new page if need to
if (!page)
{
uint64 pageSize = Math::Max<uint64>(_pageSize, size);
page = (Page*)Allocator::Allocate(sizeof(Page));
page->Memory = Allocator::Allocate(pageSize);
page->Next = _first;
page->Offset = 0;
page->Size = pageSize;
_first = page;
}
// Allocate within a page
page->Offset = Math::AlignUp(page->Offset, (uint32)alignment);
void* mem = (byte*)page->Memory + page->Offset;
page->Offset += size;
return mem;
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#include "Allocation.h"
/// <summary>
/// Allocator that uses pages for stack-based allocs without freeing memory during it's lifetime.
/// </summary>
class ArenaAllocator
{
private:
struct Page
{
void* Memory;
Page* Next;
uint32 Offset, Size;
};
int32 _pageSize;
Page* _first = nullptr;
public:
ArenaAllocator(int32 pageSizeBytes = 1024 * 1024) // 1 MB by default
: _pageSize(pageSizeBytes)
{
}
~ArenaAllocator()
{
Free();
}
// Allocates a chunk of unitialized memory.
void* Allocate(uint64 size, uint64 alignment = 1);
// Frees all memory allocations within allocator.
void Free();
// Creates a new object within the arena allocator.
template<class T, class... Args>
inline T* New(Args&&...args)
{
T* ptr = (T*)Allocate(sizeof(T));
new(ptr) T(Forward<Args>(args)...);
return ptr;
}
// Invokes destructor on values in a dictionary and clears it.
template<typename Key, typename Value, typename Allocator>
void ClearDelete(Dictionary<Key, Value, Allocator>& collection)
{
for (auto it = collection.Begin(); it.IsNotEnd(); ++it)
Memory::DestructItem(it->Value);
collection.Clear();
}
};