fix: clean up all memory leaks. use tracking allocator in example

This commit is contained in:
2025-05-25 22:44:14 +02:00
parent 8982186b72
commit 3175b3a23b
3 changed files with 48 additions and 17 deletions
-2
View File
@@ -2,5 +2,3 @@
BlurHash Implementation in Odin BlurHash Implementation in Odin
### TODO
- [ ] Clean up memory leaks
+9 -11
View File
@@ -61,9 +61,7 @@ base83_decode_str :: proc(str: string) -> int {
base83_decode :: proc{base83_decode_str, base83_decode_byte} base83_decode :: proc{base83_decode_str, base83_decode_byte}
@(private) @(private)
base83_encode :: proc(value, length: int, allocator := context.allocator) -> string { base83_encode :: proc(b: ^strings.Builder, value, length: int, allocator := context.allocator) {
b := strings.builder_make_none(allocator)
pow :: proc(base, exp: int) -> int { pow :: proc(base, exp: int) -> int {
base := base base := base
exp := exp exp := exp
@@ -80,10 +78,8 @@ base83_encode :: proc(value, length: int, allocator := context.allocator) -> str
for i in 1..=length { for i in 1..=length {
digit := (value / pow(83, length - i)) % 83 digit := (value / pow(83, length - i)) % 83
strings.write_byte(&b, ENC_TABLE[digit]) strings.write_byte(b, ENC_TABLE[digit])
} }
return strings.to_string(b)
} }
@(private) @(private)
@@ -168,6 +164,7 @@ decode :: proc(blurhash: string, width, height: int, punch := 1.0, allocator :=
colors_size := num_x * num_y colors_size := num_x * num_y
colors := make([][3]f32, colors_size) colors := make([][3]f32, colors_size)
defer delete(colors)
for iter in 0..<colors_size { for iter in 0..<colors_size {
if iter == 0 { if iter == 0 {
@@ -266,6 +263,7 @@ encode :: proc(pixels: []byte, x_components, y_components, width, height, bytes_
builder := strings.builder_make_len_cap(0, 2 + 4 + (9 * 9 - 1) * 2) builder := strings.builder_make_len_cap(0, 2 + 4 + (9 * 9 - 1) * 2)
factors := make([dynamic][3]f32, 0, x_components * y_components) factors := make([dynamic][3]f32, 0, x_components * y_components)
defer delete(factors)
for y in 0..<y_components { for y in 0..<y_components {
for x in 0..<x_components { for x in 0..<x_components {
@@ -278,7 +276,7 @@ encode :: proc(pixels: []byte, x_components, y_components, width, height, bytes_
ac := factors[1:] ac := factors[1:]
size_flag := (x_components - 1) + (y_components - 1) * 9 size_flag := (x_components - 1) + (y_components - 1) * 9
strings.write_string(&builder, base83_encode(size_flag, 1)) base83_encode(&builder, size_flag, 1)
max_value: f32 max_value: f32
@@ -290,16 +288,16 @@ encode :: proc(pixels: []byte, x_components, y_components, width, height, bytes_
quantized_max_value := int(max(0, min(82, math.floor(actual_max_value * 166 - 0.5)))) quantized_max_value := int(max(0, min(82, math.floor(actual_max_value * 166 - 0.5))))
max_value = f32(quantized_max_value + 1) / 166.0 max_value = f32(quantized_max_value + 1) / 166.0
strings.write_string(&builder, base83_encode(quantized_max_value, 1)) base83_encode(&builder, quantized_max_value, 1)
} else { } else {
max_value = 1 max_value = 1
strings.write_string(&builder, base83_encode(0, 1)) base83_encode(&builder, 0, 1)
} }
strings.write_string(&builder, base83_encode(encode_dc(dc), 4)) base83_encode(&builder, encode_dc(dc), 4)
for factor in ac { for factor in ac {
strings.write_string(&builder, base83_encode(encode_ac(factor, max_value), 2)) base83_encode(&builder, encode_ac(factor, max_value), 2)
} }
return strings.to_string(builder), nil return strings.to_string(builder), nil
+39 -4
View File
@@ -5,20 +5,24 @@ import "core:image"
import "core:image/qoi" import "core:image/qoi"
import "core:image/png" import "core:image/png"
import "core:slice" import "core:slice"
import "core:mem"
import "core:os/os2" import "core:os/os2"
import blurhash "../" import blurhash "../"
decode_example :: proc() { decode_example :: proc() {
if len(os2.args) < 3 { if len(os2.args) < 3 {
fmt.eprintln("Please the blurhash as an arg") fmt.eprintln("Please input the blurhash as an arg")
return return
} }
track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)
alloc := mem.tracking_allocator(&track)
width := 400 width := 400
height := 240 height := 240
pixels, err := blurhash.decode(os2.args[2], width, height, 1.2) pixels, err := blurhash.decode(os2.args[2], width, height, 1.2, alloc)
defer delete(pixels)
if err != nil { if err != nil {
fmt.eprintln(err) fmt.eprintln(err)
return return
@@ -35,6 +39,20 @@ decode_example :: proc() {
fmt.eprintln(save_err) fmt.eprintln(save_err)
return return
} }
delete(pixels, alloc)
for _, leak in track.allocation_map {
fmt.printfln("%v leaked %m", leak.location, leak.size)
}
for bad_free in track.bad_free_array {
fmt.printfln("%v allocation %p was freed badly", bad_free.location, bad_free.memory)
}
fmt.printfln("Peak Mem: %m", track.peak_memory_allocated)
fmt.printfln("Total Mem: %m", track.total_memory_allocated)
fmt.printfln("Current Mem: %m", track.current_memory_allocated)
fmt.printfln("Total Allocs: %v, Total Frees: %v:", track.total_allocation_count, track.total_free_count)
fmt.printfln("Total Mem Free'd: %m", track.total_memory_freed)
} }
encode_example :: proc() { encode_example :: proc() {
@@ -49,13 +67,30 @@ encode_example :: proc() {
return return
} }
bhash, hash_err := blurhash.encode(img.pixels.buf[:], 5, 4, img.width, img.height, img.width*img.channels) track: mem.Tracking_Allocator
mem.tracking_allocator_init(&track, context.allocator)
alloc := mem.tracking_allocator(&track)
bhash, hash_err := blurhash.encode(img.pixels.buf[:], 5, 4, img.width, img.height, img.width*img.channels, alloc)
if hash_err != nil { if hash_err != nil {
fmt.eprintln(hash_err) fmt.eprintln(hash_err)
return return
} }
fmt.println(bhash) fmt.println(bhash)
delete(bhash, alloc)
for _, leak in track.allocation_map {
fmt.printfln("%v leaked %m", leak.location, leak.size)
}
for bad_free in track.bad_free_array {
fmt.printfln("%v allocation %p was freed badly", bad_free.location, bad_free.memory)
}
fmt.printfln("Peak Mem: %m", track.peak_memory_allocated)
fmt.printfln("Total Mem: %m", track.total_memory_allocated)
fmt.printfln("Current Mem: %m", track.current_memory_allocated)
fmt.printfln("Total Allocs: %v, Total Frees: %v:", track.total_allocation_count, track.total_free_count)
fmt.printfln("Total Mem Free'd: %m", track.total_memory_freed)
} }
main :: proc() { main :: proc() {