memory debugger




Memory Debugger

The Basic module can wrap its allocation routines with the memory debugger:

    
#import "Basic"()(MEMORY_DEBUGGER = true);
    

With this module parameter enabled, modules/Basic/module.jai loads Memory_Debugger.jai, and alloc, free, and realloc call Memory_Debugger.check_alloc, check_free, and check_realloc. Those hooks let the debugger report leaks, double frees, unknown frees, and allocator mismatches.

If you want to drive MEMORY_DEBUGGER from a build configuration constant, see Module and Program Parameters for import-order details.

This bookkeeping uses memory of its own. In Memory_Debugger.jai, allocations are recorded in address_table. When the debugger sees a pointer address for the first time, add_allocation_to_table allocates an Allocation record from address_table_pool and stores the pointer, size, allocator, live/free state, allocation stack trace, and free stack trace. A later free marks that record as no longer live and saves the free trace; it does not remove the record from the table.

Because of this, a long-running program with lots of allocation churn can show steadily increasing process memory while the debugger is enabled. That increase can be the debugger accumulating history and stack-trace data about your program, not necessarily an application leak. If VISUALIZE_MEMORY_DEBUGGER is also enabled, the debugger keeps extra allocation/free summary tables for the live visualizer.

Live Visualization

Jai also ships a live viewer in examples/codex_view. Build that example from its directory; its build.jai sets the output executable to run/codex_view. Run codex_view, open the Allocs view, then run your program with the memory debugger enabled:

    
#import "Basic"()(MEMORY_DEBUGGER = true, VISUALIZE_MEMORY_DEBUGGER = true);
    

In a program that has a regular frame or tick, call this once per frame at a controlled point:

    
memory_visualizer_per_frame_update();
    

That procedure is defined by Visualize_Memory_Debugger.jai. It initializes the visualization channel if needed and sends the current live allocations, allocations this frame, frees this frame, and stack-trace information to codex_view. When the visualizer is not enabled, Basic defines memory_visualizer_per_frame_update as an empty procedure, so it is convenient to leave the call site in your frame loop while controlling the feature with the module parameters.

Treat MEMORY_DEBUGGER = true as a development setting. Turn it on when tracking memory problems, then turn it off for shipped builds. Shipping with it enabled can make the executable slower and can cause the process to keep reserving memory for debugger metadata until the machine runs out of available memory.