#import "std/debug_allocator"
Debug allocator can be used to analyze memory usage and eventually investigate possible memory leaks. Every allocation done via debug allocator is internally recorded with some meta-data included to each allocation. Debug allocator can later panic in situations like double-free, freeing of non-allocated memory; or just report memory usage or memory leaks.
Each allocation takes more space due to meta data beeing stored. This allocator also should not be used in production code since it's way much slower than regular allocators.
- [x] Allocate
- [x] Reallocate
- [x] Free
- [x] Release
- [ ] Reset
#import "std/debug_allocator"
debug_allocator: std.DebugAllocator;
main :: fn () s32 {
using std;
// Initialize debug allocator with current context allocator.
debug_allocator = debug_allocator_make(application_context.allocator);
// Always cleanup at the end of the scope.
defer debug_allocator_release(&debug_allocator);
// Some leaking memory.
alloc(128, DEFAULT_ALIGNMENT, &debug_allocator);
// Do some other stuff...
dump_memory_leaks(&debug_allocator);
return 0;
}
.\out.exe
Dump memory leaks begin:
[1] - C:/Develop/bl/tests/test.bl:13 (128 bytes)
Dump memory leaks end.
Note: Debug allocator can be used as global application allocator to catch all possible memory leaks and other issues.
Note: Debug allocator is thread safe.
Note: Memory freed by this allocator is set to 0xdddddddd, if you see such a pattern in the debugger, you are probably trying to use already freed memory.
DebugAllocator :: struct {
mutex: std.Mutex;
allocator: *Allocator;
total_allocated: s64;
alloc_table: ;
serial: u64;
break_on: u64;
}
File: debug_allocator.bl
debug_allocator_make :: fn (allocator: *Allocator) DebugAllocator
Create new debug allocator instance using allocator
to allocate memory.
File: debug_allocator.bl
debug_allocator_release :: fn (dbgalloc: *DebugAllocator) #inline
Release debug allocator resources.
File: debug_allocator.bl
debug_allocator_break :: fn (dbgalloc: *DebugAllocator, serial: u64) #inline
Invoke debug_break
before allocation with defined serial ID.
File: debug_allocator.bl
debug_allocator_allocated :: fn (dbgalloc: *DebugAllocator) usize #inline
Return currently allocated memory in bytes.
File: debug_allocator.bl
debug_allocator_allocated_count :: fn (dbgalloc: *DebugAllocator) s64 #inline
Return count of currently allocated memory entries.
File: debug_allocator.bl
debug_allocator_get_allocation_size :: fn (dbgalloc: *DebugAllocator, ptr: *u8) (found: bool, size: usize) #inline
Lookup size in bytes of previously allocated memory. Returns true
and size in bytes if allocation
was found, otherwise returns false
and zero size.
File: debug_allocator.bl
print_memory_report :: fn (dbgalloc: *DebugAllocator, dump_leaks :: false)
Print memory report. First block contains currently allocated bytes and current count
of allocations. Optional memory leak dump block (enabled by dump_leaks
argument) contains:
[allocation serial ID] - <file>:<line> (allocation size in bytes)
$ ./out.exe
******************* MEMORY REPORT ******************
* Allocated 64 Bytes.
* Count of allocations 1.
****************************************************
Dump memory leaks begin:
[1] - test.bl:10 (64 bytes)
Dump memory leaks end.
Note: Printed report contains all remaining (not freed) allocations in time when function was called. Memory leaks can contain false-positives when function is called before execution end.
Note: Allocation serail ID can be used by debug_allocator_break to interrupt execution before memory is allocated and eventually localize allocation in debbuger.
File: debug_allocator.bl
dump_memory_leaks :: fn (dbgalloc: *DebugAllocator) s64
Print only leaking memory if any and returs count of leaking allocations. Please see the print_memory_report for further details.
File: debug_allocator.bl