Handmade Hero » Forums » Code » Memory Arenas vs. Casting Memory
Delix
Ryan Fleury
134 posts / 1 project

Handmade Network lead and developer of The Melodist

#15812 Memory Arenas vs. Casting Memory
4 months ago Edited by Ryan Fleury on July 20, 2018, 3:48 a.m. Reason: Initial post

Hey there!

I've run into a problem in my own programming that requires an "arbitrary" (within some upper-bound) amount of memory. I rushed in to battle this beast, only to find self-doubt and reconsideration! At this point, I used Miblo's incredible episode guide to find an old Handmade Hero episode (34) to hear what the thought process of an expert was on this subject.

In this episode, Casey implements a very simple memory arena that makes use of the game's permanent storage. I have a question about this, though, and unfortunately I was not there to experience it in real-time!

To get to the point, my question is this: What are the benefits and drawbacks of say, the following...

1
2
3
4
5
6
7
8
// given some void *storage
struct MemoryForTask {
    u8 bytes_for_sub_task_1[megabytes(2)];
    u8 bytes_for_sub_task_2[megabytes(4)];
    u8 bytes_for_sub_task_3[megabytes(1)];
} *memory_for_task = (MemoryForTask *)storage;

// use memory_for_task->bytes_for_sub_task_n to allocate from and do stuff with


...and how do those compare to those of something similar to what Casey implemented?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
struct MemoryArena {
    u64 alloc_position;
    u64 memory_limit;
    u8 *memory;
};

void *alloc_from_arena(MemoryArena *arena, u64 number_of_bytes) {
    assert(arena->alloc_position + number_of_bytes <= arena->memory_limit);
    void *result = (void *)(arena->memory + arena->alloc_position);
    arena->alloc_position += number_of_bytes;
    return result;
}

// later, given some MemoryArena arena...

void *bytes_for_sub_task_1 = alloc_from_arena(&arena, megabytes(2));
void *bytes_for_sub_task_2 = alloc_from_arena(&arena, megabytes(4));
void *bytes_for_sub_task_3 = alloc_from_arena(&arena, megabytes(1));


I've tended to use the first system in the past, but I have a voice in my head suggesting I am not thinking of everything. Are there potential implications of the first system that could cause problems down the road, or are these two systems largely the same?

Thanks in advance for any responses!
Ryan

Handmade Network lead and developer of The Melodist
mmozeiko
Mārtiņš Možeiko
1826 posts / 1 project
#15813 Memory Arenas vs. Casting Memory
4 months ago

It's pretty much the same, you'll have no issues. Only disadvantage of first approach is that you cannot adjust size at runtime due to some condition. Sizes are compile-time constants.
mrmixer
Simon Anciaux
480 posts
#15822 Memory Arenas vs. Casting Memory
3 months, 4 weeks ago

A detail is that the arena method doesn't align memory (Casey later adds memory alignment). But that doesn't matter in your example case.
The arena method will assert if the arena doesn't have enough memory for the tasks. And you could use arenas for the sub tasks memory to also have the overflow assert if you allocate using alloc_from_arena.

If you need to keep the memory footprint of the application as low as possible, you could take advantage of the virtual memory by reserving a certain amount of memory, and only committing x megabytes. When you reach x megabytes, commit y megabytes more... But that's probably more suitable for "systems memory" than for "tasks memory".