Handmade Hero»Forums»Code
19 posts
Clearing memory arenas efficiently

Until day 342, the Clear function on arenas looked like this:

inline void
InitializeArena(memory_arena *Arena, memory_index Size, void *Base)
{
    Arena->Size = Size;
    Arena->Base = (uint8 *)Base;
    Arena->Used = 0;
    Arena->TempCount = 0;
    Arena->MinimumBlockSize = 0;
}

inline void
Clear(memory_arena *Arena)
{
    InitializeArena(Arena, Arena->Size, Arena->Base);
}

So in this case, clearing the arena is basically free. But on day 342, after having added support for growing arenas, the clear function has changed to:

inline void
FreeLastBlock(memory_arena *Arena)
{
    void *Free = Arena->Base;
    
    memory_block_footer *Footer = GetFooter(Arena);
    
    Arena->Base = Footer->Base;
    Arena->Size = Footer->Size;
    Arena->Used = Footer->Used;
    
    Platform.DeallocateMemory(Free);
    
    --Arena->BlockCount;
}

inline void
Clear(memory_arena *Arena)
{
    while(Arena->BlockCount > 0)
    {
        FreeLastBlock(Arena);
    }
}

Does this means that arenas cannot be reinitialized like before with just some assignment, without deallocating the memory? Isn't that a step back?

Maybe we can use temporary_memory, because as long as we allocate off of the same block, there is no actual deallocation:

inline void
EndTemporaryMemory(temporary_memory TempMem)
{
    memory_arena *Arena = TempMem.Arena;
    while(Arena->Base != TempMem.Base)
    {
        FreeLastBlock(Arena);
    }
    
    Assert(Arena->Used >= TempMem.Used);
    Arena->Used = TempMem.Used;
    Assert(Arena->TempCount > 0);
    --Arena->TempCount;
}

So ending temporary memories is still "fast" without deallocating, but only if we didn't pushed too much on the temporary memory, because in that case, EndTemporaryMemory will actually free the additional blocks.

This means that we can only guarantee that ending the temporary memory that it's "fast" if we don't overflow the current block, because otherwise we'll have to deallocate memory.

So did we really lose the ability to clear the memory with just some assignments? Or at least we lost the guarantee that it'll be fast (because we may have pushed too much on the temporary memory)? I thought that it was important in games to avoid deallocating the memory every frame.

Simon Anciaux
1337 posts
Clearing memory arenas efficiently

terans
So did we really lose the ability to clear the memory with just some assignments?
Yes
terans
Or at least we lost the guarantee that it'll be fast (because we may have pushed too much on the temporary memory)? I thought that it was important in games to avoid deallocating the memory every frame.
It's slower, but keep in mind that there will not be much calls to VirtualAlloc and VirtualFree as, if I remember correctly, there aren't a lot of memory blocks allocated (I believe it's less than 10 but I didn't measure that).

When the memory lifetime is long there is no issue with this as it results with rare call to VirtualAlloc and VirtualFree.

When the memory lifetime is a frame or less, we generally have blocks big enough (you can do a lot with 1MB) to accommodate lots of small memory allocations without the need to create a lot of new blocks; and things that needs more than a single block size (which are less common) still get a big continuous block at the cost of a VirtualAlloc and a VirtualFree call.

In the end, if you want to know the impact on performance, you need to profile both systems. I suspect the difference will be very small.

19 posts
Clearing memory arenas efficiently
Replying to mrmixer (#25378)

Ok thank you