fix wrong out of memory in edge cases, just try allocate from block for one source of truth

This commit is contained in:
Laytan Laats
2025-02-12 19:09:21 +01:00
parent 4c4b481ccc
commit 7df5be2131
4 changed files with 43 additions and 12 deletions
@@ -105,12 +105,14 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio
return return
} }
needed := align_forward_uint(size, alignment) prev_used := 0 if arena.curr_block == nil else arena.curr_block.used
if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.capacity { data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
if err == .Out_Of_Memory {
if arena.minimum_block_size == 0 { if arena.minimum_block_size == 0 {
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
} }
needed := align_forward_uint(size, alignment)
block_size := max(needed, arena.minimum_block_size) block_size := max(needed, arena.minimum_block_size)
if arena.backing_allocator.procedure == nil { if arena.backing_allocator.procedure == nil {
@@ -121,10 +123,9 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio
new_block.prev = arena.curr_block new_block.prev = arena.curr_block
arena.curr_block = new_block arena.curr_block = new_block
arena.total_capacity += new_block.capacity arena.total_capacity += new_block.capacity
prev_used = 0
data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
} }
prev_used := arena.curr_block.used
data, err = alloc_from_memory_block(arena.curr_block, size, alignment)
arena.total_used += arena.curr_block.used - prev_used arena.total_used += arena.curr_block.used - prev_used
return return
} }
+7 -5
View File
@@ -107,8 +107,9 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
switch arena.kind { switch arena.kind {
case .Growing: case .Growing:
needed := mem.align_forward_uint(size, alignment) prev_used := 0 if arena.curr_block == nil else arena.curr_block.used
if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.reserved { data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size)
if err == .Out_Of_Memory {
if arena.minimum_block_size == 0 { if arena.minimum_block_size == 0 {
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
arena.minimum_block_size = mem.align_forward_uint(arena.minimum_block_size, DEFAULT_PAGE_SIZE) arena.minimum_block_size = mem.align_forward_uint(arena.minimum_block_size, DEFAULT_PAGE_SIZE)
@@ -124,6 +125,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
max(arena.default_commit_size, arena.minimum_block_size) max(arena.default_commit_size, arena.minimum_block_size)
} }
needed := mem.align_forward_uint(size, alignment)
needed = max(needed, arena.default_commit_size) needed = max(needed, arena.default_commit_size)
block_size := max(needed, arena.minimum_block_size) block_size := max(needed, arena.minimum_block_size)
@@ -131,10 +133,10 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
new_block.prev = arena.curr_block new_block.prev = arena.curr_block
arena.curr_block = new_block arena.curr_block = new_block
arena.total_reserved += new_block.reserved arena.total_reserved += new_block.reserved
}
prev_used := arena.curr_block.used prev_used = 0
data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size) data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size)
}
arena.total_used += arena.curr_block.used - prev_used arena.total_used += arena.curr_block.used - prev_used
case .Static: case .Static:
if arena.curr_block == nil { if arena.curr_block == nil {
+14
View File
@@ -1,6 +1,7 @@
package test_core_mem package test_core_mem
import "core:mem/tlsf" import "core:mem/tlsf"
import "core:mem/virtual"
import "core:testing" import "core:testing"
@test @test
@@ -39,3 +40,16 @@ test_tlsf_bitscan :: proc(t: ^testing.T) {
} }
} }
} }
@(test)
test_align_bumping_block_limit :: proc(t: ^testing.T) {
a: virtual.Arena
data, err := virtual.arena_alloc(&a, 4193371, 1)
testing.expect_value(t, err, nil)
testing.expect(t, len(data) == 4193371)
data, err = virtual.arena_alloc(&a, 896, 64)
testing.expect_value(t, err, nil)
testing.expect(t, len(data) == 896)
}
+14
View File
@@ -31,6 +31,20 @@ test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) {
testing.expect(t, err == nil) testing.expect(t, err == nil)
} }
@(test)
test_align_bumping_block_limit :: proc(t: ^testing.T) {
a: runtime.Arena
a.minimum_block_size = 8*mem.Megabyte
data, err := runtime.arena_alloc(&a, 4193371, 1)
testing.expect_value(t, err, nil)
testing.expect(t, len(data) == 4193371)
data, err = runtime.arena_alloc(&a, 896, 64)
testing.expect_value(t, err, nil)
testing.expect(t, len(data) == 896)
}
@(test) @(test)
test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) { test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) {
arena: runtime.Arena arena: runtime.Arena