Add new Arena Allocator for optimized dynamic memory allocations with a shared lifetime
This commit is contained in:
44
Source/Engine/Core/Memory/Allocation.cpp
Normal file
44
Source/Engine/Core/Memory/Allocation.cpp
Normal 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;
|
||||||
|
}
|
||||||
55
Source/Engine/Core/Memory/ArenaAllocation.h
Normal file
55
Source/Engine/Core/Memory/ArenaAllocation.h
Normal 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();
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user