Debug Allocator

#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.

Example

#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_terminate(&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 patern in the debugger, you are probably trying to used already freed data.

std.DebugAllocator

DebugAllocator :: struct {
    mutex: std.Mutex;
    allocator: *Allocator;
    total_allocated: s64;
    alloc_table: ;
    serial: u64;
    break_on: u64;
 }

File: debug_allocator.bl

std.debug_allocator_make

debug_allocator_make :: fn (allocator: *Allocator) DebugAllocator

Create new debug allocator instace using allocator to allocate memory.

File: debug_allocator.bl

std.debug_allocator_terminate

debug_allocator_terminate :: fn (dbgalloc: *DebugAllocator) 

Release debug allocator resources.

File: debug_allocator.bl

std.debug_allocator_break

debug_allocator_break :: fn (dbgalloc: *DebugAllocator, serial: u64)  #inline

Invoke debug_break before allocation with defined serial ID.

File: debug_allocator.bl

std.debug_allocator_allocated

debug_allocator_allocated :: fn (dbgalloc: *DebugAllocator) usize #inline

Return currently allocated memory in bytes.

File: debug_allocator.bl

std.debug_allocator_get_allocation_size

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

std.print_memory_report

print_memory_report :: fn (dbgalloc: *DebugAllocator, dump_leaks :: ) 

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

std.dump_memory_leaks

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