I’ve been thinking about ways to handle memory in Odin. I used to use both allocators in context a lot, but after seeing Bill say multiple times that I’m using it outside its intended use, I started trying other ways.
I also read in some places that I should be using virtual memory allocators, if my platform supports it. So I’m trying to do that.
I was wondering if doing something like this is acceptable for a “temp” allocator that clears every frame, or for other uses like “all memory associated with a game scene”:
package allocators
import "core:fmt"
import "core:mem/virtual"
import "core:mem"
import "base:runtime"
arena : virtual.Arena
arena_alloc : mem.Allocator
print_arena :: proc(desc: string) {
fmt.printf(desc)
fmt.printfln(" - us: %v, reserved: %v", arena.total_used, arena.total_reserved)
}
main :: proc() {
alloc_err := virtual.arena_init_growing(&arena, 1000)
assert(alloc_err == .None)
arena_alloc = virtual.arena_allocator(&arena)
print_arena("init")
data := make([]byte, 100, arena_alloc)
print_arena("after a make")
do_thing()
print_arena("after proc")
}
do_thing :: proc() {
TEMP_GUARD(&arena)
// equal to:
// temp := virtual.arena_temp_begin(&arena)
// defer virtual.arena_temp_end(temp)
print_arena("in proc - before make")
data := make([]byte, 23000, arena_alloc)
print_arena("in proc - after make")
}
// Convenience function for clearing used memory in scope
@(deferred_out=virtual.arena_temp_end)
TEMP_GUARD :: #force_inline proc(arena: ^virtual.Arena, loc := #caller_location) -> (virtual.Arena_Temp, runtime.Source_Code_Location) {
return virtual.arena_temp_begin(arena, loc), loc
}
// Output:
/*
init - us: 0, reserved: 4096
after a make - us: 100, reserved: 4096
in proc - before make - us: 100, reserved: 4096
in proc - after make - us: 23100, reserved: 28672
after proc - us: 100, reserved: 4096
*/
For long lasting allocations that should live throughout the whole program, I was thinking of using the Scratch allocator wrapped in a Tracking allocator.
Some questions:
1: Does the code make sense?
2: I’ve heard that we should probably allocate memory in allocators directly, instead of using them through the runtime.Allocator interface. Isn’t the unified interface convenient, because of make() and others?
3: Why is there only the Arena type allocator in mem/virtual?
References: Temporary allocators and the core library