# How to Implement Custom Memory Allocators for Dear ImGui

> Learn how to implement custom memory allocators for Dear ImGui by replacing default functions. Optimize your Dear ImGui application's memory management efficiently.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-26

---

**Dear ImGui delegates all dynamic memory operations to function pointers that you can replace with custom implementations via `ImGui::SetAllocatorFunctions()` before calling `ImGui::CreateContext()`.**

Dear ImGui uses a callback-based memory allocation system that lets you intercept every internal malloc and free operation. This article explains how to implement custom memory allocators for Dear ImGui by hooking into the `ImGuiMemAllocFunc` and `ImGuiMemFreeFunc` function pointers defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h). Whether you need memory tracking, arena allocators, or integration with existing engine systems, you'll learn the exact API signatures and global hooks used in the `ocornut/imgui` source code.

## Understanding the Allocation API

The memory allocator interface consists of two function type definitions and a user-data pointer that ImGui passes through on every allocation.

### Function Pointer Types

In [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) (around line 288), Dear ImGui declares the allocator signatures as `typedef` function pointers:

```cpp
typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data);
typedef void  (*ImGuiMemFreeFunc)(void* ptr, void* user_data);

```

Your custom allocator must match these signatures exactly. The `user_data` parameter allows you to pass an opaque pointer—typically a struct containing your allocator state—through to every allocation and deallocation call.

### Default Implementation

If you do not install custom callbacks, ImGui falls back to standard `malloc`/`free` wrappers defined in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) (around line 1493):

```cpp
static void* MallocWrapper(size_t size, void* user_data) {
    IM_UNUSED(user_data);
    return malloc(size);
}
static ImGuiMemAllocFunc GImAllocatorAllocFunc = MallocWrapper;

```

All internal ImGui allocations flow through the global function pointers `GImAllocatorAllocFunc` and `GImAllocatorFreeFunc`, which default to these wrappers.

## Installing Custom Allocators

You must configure your custom allocator **before** creating any ImGui context.

### SetAllocatorFunctions

Call `ImGui::SetAllocatorFunctions()` early in your application initialization—specifically before `ImGui::CreateContext()`. The function is implemented in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) (around line 4164):

```cpp
void ImGui::SetAllocatorFunctions(
    ImGuiMemAllocFunc alloc_func, 
    ImGuiMemFreeFunc free_func, 
    void* user_data
);

```

The `user_data` pointer is stored globally and passed to your callbacks on every subsequent allocation. After this call, ImGui redirects all internal memory requests through your supplied functions.

### Memory Allocation Entry Points

Once installed, your callbacks are invoked by `ImGui::MemAlloc` and `ImGui::MemFree` (defined in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) around line 5169):

```cpp
void* ImGui::MemAlloc(size_t size) {
    void* ptr = (*GImAllocatorAllocFunc)(size, GImAllocatorUserData);
    // ... debug tracking ...
    return ptr;
}

void ImGui::MemFree(void* ptr) {
    (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData);
}

```

These functions handle every dynamic allocation within ImGui, including font atlas storage, window state, draw lists, and string duplication.

## Practical Implementation Examples

Below are three common patterns for supplying custom allocators to Dear ImGui.

### Example 1: Instrumented malloc Wrapper with Bookkeeping

This implementation tracks total allocated bytes for profiling purposes:

```cpp
static size_t g_total_alloc = 0;

void* MyAlloc(size_t size, void* /*user_data*/) {
    g_total_alloc += size;
    return malloc(size);
}

void MyFree(void* ptr, void* /*user_data*/) {
    free(ptr);
}

int main() {
    ImGui::SetAllocatorFunctions(MyAlloc, MyFree, nullptr);
    ImGui::CreateContext();
    // ... ImGui now uses MyAlloc/MyFree for all internal allocations
}

```

### Example 2: Linear Arena Allocator

For frame-based allocation patterns where you reset memory wholesale each frame, use a linear arena. Note that individual frees are no-ops; you must reset the arena offset manually:

```cpp
struct LinearArena {
    uint8_t* buffer;
    size_t   capacity;
    size_t   offset;
};

void* ArenaAlloc(size_t size, void* user_data) {
    LinearArena* arena = static_cast<LinearArena*>(user_data);
    if (arena->offset + size > arena->capacity) return nullptr;
    void* ptr = arena->buffer + arena->offset;
    arena->offset += size;
    return ptr;
}

void ArenaFree(void* /*ptr*/, void* /*user_data*/) {
    // No-op: memory is reclaimed by resetting arena.offset
}

// Usage
int main() {
    static uint8_t raw[4*1024*1024];
    LinearArena arena = { raw, sizeof(raw), 0 };
    
    ImGui::SetAllocatorFunctions(ArenaAlloc, ArenaFree, &arena);
    ImGui::CreateContext();
    
    // Each frame:
    // arena.offset = 0;  // Reset entire pool
}

```

### Example 3: C++ std::pmr::memory_resource Wrapper

Integrate with C++17 polymorphic memory resources to leverage `monotonic_buffer_resource` or third-party allocators like tcmalloc or mimalloc:

```cpp
#include <memory_resource>

void* PmrAlloc(size_t size, void* user_data) {
    return static_cast<std::pmr::memory_resource*>(user_data)->allocate(size);
}

void PmrFree(void* ptr, void* user_data) {
    // std::pmr requires size for deallocate, but ImGui doesn't track it.
    // Using monotonic_buffer_resource makes this safe.
    static_cast<std::pmr::memory_resource*>(user_data)->deallocate(ptr, 0);
}

int main() {
    std::pmr::monotonic_buffer_resource pool{
        std::malloc(8*1024*1024), 8*1024*1024
    };
    
    ImGui::SetAllocatorFunctions(PmrAlloc, PmrFree, &pool);
    ImGui::CreateContext();
}

```

## Querying Current Allocators

To retrieve the currently installed allocator for debugging or when copying state across DLL boundaries, use `ImGui::GetAllocatorFunctions()` (defined in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp) around line 4171):

```cpp
void ImGui::GetAllocatorFunctions(
    ImGuiMemAllocFunc* p_alloc_func, 
    ImGuiMemFreeFunc* p_free_func, 
    void** p_user_data
);

```

This copies the global function pointers and user data to the provided addresses, allowing you to verify which allocator is active or propagate the same allocator to another module.

## Summary

- **Hook early**: Call `ImGui::SetAllocatorFunctions()` with your `ImGuiMemAllocFunc` and `ImGuiMemFreeFunc` implementations before `ImGui::CreateContext()`.
- **Use `user_data`**: Pass allocator state (pools, tracking counters) through the opaque `void*` parameter available in both allocation and deallocation callbacks.
- **Centralized routing**: All ImGui allocations flow through `ImGui::MemAlloc` and `ImGui::MemFree` in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), which dispatch to your installed function pointers.
- **Type definitions**: Implementations must match the signatures declared in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 288, including the `size_t` and `void* user_data` parameters.
- **Retrieval API**: Use `ImGui::GetAllocatorFunctions()` to inspect the current allocator configuration at runtime.

## Frequently Asked Questions

### When must I set the custom allocator relative to context creation?

You must call `ImGui::SetAllocatorFunctions()` **before** `ImGui::CreateContext()`. The library caches the function pointers during context initialization, and allocations occurring during context setup (such as font atlas building) will use whatever allocator is currently installed. Calling the setter after context creation leaves the default allocator active for the lifetime of that context.

### Can I use different allocators for different ImGui contexts?

No. Dear ImGui uses **global** function pointers (`GImAllocatorAllocFunc` and `GImAllocatorFreeFunc` in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp)) rather than per-context allocators. All contexts within the same process share the same allocation functions. If you need isolation, implement a custom allocator that internally dispatches based on thread ID or user_data rather than replacing the global hooks per context.

### How do I handle the missing size parameter in the free callback?

The `ImGuiMemFreeFunc` signature only receives the pointer and user_data, not the original allocation size. If your custom allocator requires size information for deallocation (as `std::pmr::memory_resource` does), you must track sizes externally or use allocation strategies that do not require per-block metadata, such as monotonic arenas or malloc-based wrappers that ignore the size during free.

### Does ImGui allocate memory during the frame, or only during setup?

ImGui allocates memory both during initial context creation and continuously during frame execution. Operations like `ImGui::Begin()` for new windows, text rendering, and widget state management trigger allocations through `ImGui::MemAlloc`. Therefore, your custom allocator must remain valid and performant for the entire application lifetime, not just during initialization.