Skip to content

dragonGR/AdvancedMemoryManager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AdvancedMemoryManager

AdvancedMemoryManager is a focused C toolkit for aligned allocations, reusable memory pools, arena-style scratch allocation, lightweight reference counting, tagged allocations, and allocator diagnostics. The project started as a compact learning exercise and is now being shaped into something much more practical: a small, readable allocator toolkit that is safe to study, easy to benchmark, and straightforward to extend.

Why this repository matters

Most memory manager examples online stop right where things become interesting. They show an allocation trick or a toy free list, but they rarely keep enough metadata around to make free, realloc, reporting, and pool reuse behave like a coherent system.

This repository is meant to close that gap.

The current toolkit is built around a few principles:

  • Keep ownership explicit.
  • Make aligned allocation correct, not approximate.
  • Reuse memory pools when they help, and fall back to the heap when they do not.
  • Offer a fast arena path for short-lived scratch allocations.
  • Expose useful runtime statistics instead of hiding allocator behavior.
  • Make it easy to see which subsystem or workload is actually consuming memory.
  • Surface misuse early with lightweight debug hooks instead of silent failure.
  • Keep the code readable enough that someone can learn from it without fighting the implementation.

What the toolkit offers today

  • Aligned allocation with raw-pointer tracking, so release and resize paths stay correct.
  • Fixed-size memory pools for predictable reuse on common allocation sizes.
  • Arena allocation for frame-based, request-scoped, or scratch-buffer workloads.
  • Heap fallback for requests that do not match an existing pool.
  • Reference counting for shared allocations that need explicit retain and release semantics.
  • Runtime statistics for active bytes, peak usage, pool hits, heap hits, failed allocations, and invalid ownership operations.
  • Pool inspection helpers for diagnostics and tooling.
  • Debug hooks for invalid retain, release, and realloc usage.
  • Faster active-allocation bookkeeping through an internal pointer index and constant-time unlinking for live blocks.
  • Tagged allocations and tag snapshots for lightweight subsystem-level profiling.
  • A demo program that exercises the public API end to end.
  • A small test suite that checks alignment, pool roundtrips, arena reset behavior, reallocation, zeroed allocation, reference counting, and misuse detection.
  • A benchmark target for comparing malloc/free, pool-backed allocations, and arena resets.

Repository layout

.
├── include/
│   └── advanced_memory_manager.h
├── src/
│   └── advanced_memory_manager.c
├── benchmarks/
│   └── benchmark_allocators.c
├── tests/
│   └── test_memory_manager.c
├── Makefile
└── mem_manager.c
  • include/advanced_memory_manager.h: public API for the allocator toolkit
  • src/advanced_memory_manager.c: allocator core, metadata handling, pools, and reporting
  • benchmarks/benchmark_allocators.c: rough performance comparison between standard allocation, pool reuse, and arena resets
  • tests/test_memory_manager.c: validation for the most important behaviors
  • mem_manager.c: a small demo entrypoint that shows how the toolkit is meant to be used

Build and test

Build the demo and run the tests:

make all

Build only the demo:

make demo

Run the test suite:

make test

Run the tests with sanitizers:

make sanitize

Run the benchmark target:

make benchmark

Clean generated binaries:

make clean

Quick example

#include "advanced_memory_manager.h"

int main(void) {
    AmmManager* manager = amm_create();
    int* values;

    if (manager == NULL) {
        return 1;
    }

    amm_add_pool(manager, 64, 16, 16);
    values = (int*)amm_alloc(manager, 8 * sizeof(int), 16);

    if (values != NULL) {
        values = (int*)amm_realloc(manager, values, 16 * sizeof(int), 16);
        amm_release(manager, values);
    }

    amm_destroy(manager);
    return 0;
}

Public API snapshot

Core lifecycle:

  • amm_create
  • amm_destroy

Pool management:

  • amm_add_pool
  • amm_get_pool_count
  • amm_get_pool_stats

Arena lifecycle:

  • amm_arena_create
  • amm_arena_alloc
  • amm_arena_reset
  • amm_arena_get_stats
  • amm_arena_destroy

Allocation helpers:

  • amm_alloc
  • amm_alloc_tagged
  • amm_calloc
  • amm_calloc_tagged
  • amm_realloc
  • amm_realloc_tagged
  • amm_clone
  • amm_clone_tagged

Ownership and validation:

  • amm_retain
  • amm_release
  • amm_contains

Diagnostics:

  • amm_get_stats
  • amm_get_tag_count
  • amm_get_tag_snapshot
  • amm_print_report
  • amm_set_debug_hook
  • amm_arena_print_report

What changed from the original prototype

The old single-file version was honest about its limitations, but it still had a few structural issues that kept it in demo territory:

  • aligned allocations did not retain the original raw pointer
  • release and resize flows could not be fully correct
  • pool ownership was inferred indirectly instead of stored directly
  • diagnostics existed, but the internals were not trustworthy enough yet

The new version fixes those foundations first, then layers arena allocation, debug hooks, and benchmarks on top of them. That order matters more than adding clever allocator tricks on top of a shaky base.

Arena allocator notes

The arena API is intentionally simple. It is designed for temporary memory where allocations move forward quickly and the entire region can be reset in one shot.

That makes it a good fit for:

  • per-frame data in small engines and visual tools
  • request-scoped scratch memory
  • parser or serializer work buffers
  • temporary staging memory in benchmarks
  • allocation profiling by subsystem when combined with allocator tags

It is not intended for general-purpose ownership graphs. If memory needs independent release semantics, the manager and pool APIs are the better fit.

Debug hook notes

The debug hook is there to catch suspicious allocator use while the program is still easy to reason about. Right now it reports:

  • invalid retain attempts
  • invalid release attempts
  • invalid realloc attempts
  • pool creation failures

The hook is intentionally lightweight. It gives you a place to log, count, or escalate allocator misuse without forcing a heavyweight logging framework into the library.

Tagged allocation notes

Tagged allocations are meant for the moment when raw allocator totals stop being enough. Knowing that memory is active is useful. Knowing that the bytes belong to cache, parser, scene, frame, or network is much more actionable.

The tagging layer stays intentionally small:

  • amm_alloc_tagged
  • amm_calloc_tagged
  • amm_realloc_tagged
  • amm_clone_tagged
  • amm_get_tag_count
  • amm_get_tag_snapshot

If a tag is not provided, the allocator falls back to untagged.

This is not meant to replace a full observability stack. It is meant to make day-to-day allocator profiling far easier while keeping the library compact.

Benchmark notes

The benchmark target is meant to be comparative, not absolute. It is useful for checking trends on your machine after changes to the allocator, but it should not be treated as a universal truth about allocator performance.

On the current sandbox run, the rough numbers came out like this:

  • malloc/free: about 312 ms
  • pool path: about 831 ms
  • arena path: about 118 ms

That result is a useful reminder that a small allocator toolkit still needs measurement and iteration. The arena path already shines for reset-heavy workloads, and the pool path improved substantially after the manager-side lookup and active-list unlink optimizations, but it still has room to improve.

Roadmap

This repository can become a genuinely strong systems-programming toolkit if it keeps growing in the right order. The next useful upgrades are:

  • pool fast-path improvements so benchmarks better reflect the intended design
  • configurable debug hooks for stricter policies, including abort-on-misuse modes
  • optional thread-safe wrappers for shared runtime environments
  • richer diagnostics export for CLI tools or dashboards

Good use cases

  • learning how allocator metadata is designed in real code
  • experimenting with aligned allocation strategies
  • building fixed-size pool allocators for embedded or performance-sensitive work
  • profiling allocation patterns in small systems projects
  • using a compact C codebase for interviews, workshops, or systems exercises

Project direction

The goal is not to become a drop-in replacement for industrial allocators overnight. The goal is to become one of the clearest and most useful allocator toolkits in its size class: small enough to read in an evening, solid enough to trust in experiments, and structured well enough to keep improving without turning into a mess.

About

Production-focused C allocator toolkit with aligned allocation pool allocators diagnostics and benchmark-driven memory experiments.

Topics

Resources

Stars

Watchers

Forks

Contributors