# How to Manage Dear ImGui Memory Usage: Custom Allocators and Debug Tools

> Effectively manage Dear ImGui memory usage with custom allocators and debug tools. Optimize your application by implementing pool allocation and tracking.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: best-practices
- Published: 2026-07-28

---

**Dear ImGui allows you to control memory usage by replacing its default malloc/free wrappers with custom allocator functions via `ImGui::SetAllocatorFunctions`, enabling pool allocation, tracking, and integration with engine memory systems.**

Every allocation in Dear ImGui routes through configurable function pointers rather than hard-coded system calls. By default, the library uses simple wrappers around standard `malloc` and `free` defined in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), but you can override these hooks to optimize for real-time constraints, reduce fragmentation, or integrate with your engine's memory management. This guide covers the implementation details in the `ocornut/imgui` repository and provides practical strategies for monitoring and controlling memory consumption.

## Replace the Default Allocator with Custom Hooks

Dear ImGui stores its allocation functions in the static function pointers `GImAllocatorAllocFunc` and `GImAllocatorFreeFunc` located at lines 1499–1501 of [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp). The default implementations, `MallocWrapper` and `FreeWrapper`, appear at lines 14–93 and 14–94 respectively. All internal allocations use the macros `IM_ALLOC()` and `IM_FREE()`, which resolve to `ImGui::MemAlloc()` and `ImGui::MemFree()` (lines 5168–5188).

To install a custom allocator, call `ImGui::SetAllocatorFunctions` (lines 4164–4169) before creating your first ImGui context:

```cpp
// Custom allocation functions with user_data support
void* MyAlloc(size_t size, void* user_data) {
    // Example: allocate from a fixed-size pool
    return PoolAllocate(size);
}

void MyFree(void* ptr, void* user_data) {
    // Example: return memory to pool
    PoolFree(ptr);
}

// Install hooks early in main()
ImGui::SetAllocatorFunctions(MyAlloc, MyFree, nullptr);
ImGui::CreateContext();

```

You can retrieve the current hooks at any time using `ImGui::GetAllocatorFunctions` (lines 4170–4176). This is useful for chaining allocators or temporarily swapping implementations.

### Example: Stack-Based Pool Allocator

For embedded systems or frame-based allocation, implement a linear allocator that resets each frame:

```cpp
struct StackAllocator {
    uint8_t* base;
    size_t size;
    size_t offset;
};

void* StackAlloc(size_t sz, void* user) {
    StackAllocator* a = (StackAllocator*)user;
    if (a->offset + sz > a->size) return nullptr;
    void* ptr = a->base + a->offset;
    a->offset += sz;
    return ptr;
}

void StackFree(void* /*ptr*/, void* /*user*/) {
    // No-op; memory reset via offset=0 each frame
}

// Usage
static uint8_t buffer[1<<20];
StackAllocator stack = { buffer, sizeof(buffer), 0 };
ImGui::SetAllocatorFunctions(StackAlloc, StackFree, &stack);

```

## Monitor Memory Usage with Debug Tools

When compiled without `IMGUI_DISABLE_DEBUG_TOOLS`, Dear ImGui tracks every allocation in the context's `DebugAllocInfo` structure. The counters `DebugMemAllocCount` and `DebugMemFreeCount` increment inside `MemAlloc` and `MemFree` (see `DebugAllocHook` calls at lines 5172–5175 and 5182–5185).

To view live statistics, call `ImGui::ShowMetricsWindow()`:

```cpp
ImGui::ShowMetricsWindow();  // Displays allocation count and total bytes

```

The Metrics window shows the difference between `g.DebugMemAllocCount` and `g.DebugMemFreeCount`, revealing active allocations. If these values grow continuously across frames, you have a leak in your ImGui usage patterns.

### Example: Logging Allocator for Diagnostics

Redirect allocations to a log file to trace specific leaks:

```cpp
void* LogAlloc(size_t sz, void* ud) {
    void* p = malloc(sz);
    fprintf((FILE*)ud, "ALLOC %zu -> %p\n", sz, p);
    return p;
}

void LogFree(void* p, void* ud) {
    fprintf((FILE*)ud, "FREE %p\n", p);
    free(p);
}

// Setup
FILE* log = fopen("imgui_mem.log", "w");
ImGui::SetAllocatorFunctions(LogAlloc, LogFree, log);

```

## Best Practices for Different Scenarios

**Short-lived UI elements** (pop-ups, tooltips): Rely on the default allocator. Dear ImGui automatically frees transient widget memory at the end of each frame.

**Heavy-weight resources** (fonts, large vertex buffers): Load once and cache handles. Use `ImGuiIO::Fonts->AddFontFromFileTTF` to leverage the internal font atlas rather than repeatedly allocating custom buffers. Avoid calling `ImGui::MemAlloc` directly for large temporary buffers.

**Real-time constraints** (games, embedded systems): Implement a pool or arena allocator and call `SetAllocatorFunctions` before `ImGui::CreateContext()`. This eliminates system allocator overhead and prevents fragmentation during gameplay.

**Debugging leaks**: Ensure `IMGUI_DEBUG_TOOLS` is enabled (default in debug builds). Monitor the Metrics window or log the difference between allocation and free counts to identify unfreed memory.

**Multi-threaded rendering**: The allocator you provide must be thread-safe, or you must confine all Dear ImGui calls to a single thread. Dear ImGui does not synchronize allocator access internally.

## Low-Level Memory Allocation Macros

Use `IM_ALLOC(size)` and `IM_FREE(ptr)` (documented at line 2597 of [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)) when you need to allocate memory that Dear ImGui will not manage. These macros ensure consistency with the active allocator:

```cpp
char* buffer = (char*)IM_ALLOC(256);
strcpy(buffer, "Persistent data");
// ... use buffer ...
IM_FREE(buffer);

```

**Critical warning**: Never mix `malloc`/`free` with `ImGui::MemAlloc`/`ImFree` when using a custom allocator. Always pair allocations and deallocations through the same API to avoid crashes in custom pool implementations.

## Summary

- Dear ImGui routes all allocations through function pointers `GImAllocatorAllocFunc` and `GImAllocatorFreeFunc` stored in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp).
- Override the default malloc/free wrappers using `ImGui::SetAllocatorFunctions()` before creating any context.
- Use `IM_ALLOC()` and `IM_FREE()` macros for manual allocations to respect the active allocator.
- Enable debug tools to track `DebugMemAllocCount` and `DebugMemFreeCount` via the Metrics window.
- For real-time applications, implement a pool or stack allocator to eliminate system allocation overhead and fragmentation.

## Frequently Asked Questions

### Can I use a custom memory pool with Dear ImGui?

Yes. Implement `void* MyAlloc(size_t size, void* user_data)` and `void MyFree(void* ptr, void* user_data)`, then pass them to `ImGui::SetAllocatorFunctions()`. This allows integration with engine pool allocators, arena allocators, or stack-based schemes. Call this function before `ImGui::CreateContext()` to ensure all ImGui memory uses your pool.

### How do I track memory leaks in Dear ImGui?

Compile without `IMGUI_DISABLE_DEBUG_TOOLS` and open the Metrics window with `ImGui::ShowMetricsWindow()`. The window displays active allocations by comparing `DebugMemAllocCount` and `DebugMemFreeCount`. Alternatively, install a logging allocator using `SetAllocatorFunctions` to write every allocation and free to a file for post-run analysis.

### Is Dear ImGui's default allocator thread-safe?

The default malloc/free wrappers are only as thread-safe as the underlying C runtime library. Dear ImGui itself does not add synchronization around allocator calls. If you access ImGui from multiple threads, you must provide a thread-safe allocator or restrict all ImGui API calls to a single thread.

### When should I call SetAllocatorFunctions?

Call `ImGui::SetAllocatorFunctions` immediately after initializing your application but before calling `ImGui::CreateContext()`. Setting the allocator after context creation leaves early allocations (including the context itself) using the previous allocator, potentially causing mismatched free operations when you later destroy the context.