C Memory

ReMem

A lightweight memory recycler and garbage collector for C, built for predictable performance without a runtime.

C Memory GC v0.2.0
GitHub → Blog Post →
O(1) page lookups
1.39× overhead vs malloc/free
8–9× faster than Python (low-end HW)
0 dependencies

Overview

ReMem started as an experiment to see how far you can push higher-level memory conveniences without leaving C. Writing hobby kernels, interpreters, and ML primitives made it clear how much time gets sunk into manual allocation hygiene. ReMem is a tool that feels safe enough for prototypes yet light enough for systems projects — no runtime required.

Design Goals

  • Compatibility first. No external dependencies. Works on Linux, macOS, Apple Silicon, and older x86 hardware without modification.
  • Predictable performance. Allocations route through size-classed arenas and resolve in O(1). Freed pages are recycled rather than returning to the OS on every free.
  • Drop-in ergonomics. The API mirrors malloc/free, so existing projects can adopt it incrementally with optional hooks for rooting GC-managed pointers.

How It Works

ReMem groups allocations into size classes, storing them inside arena-backed pages. When a block is freed, the collector marks it for reuse. Pages that drain completely are either cached in-memory or returned to the underlying arena depending on the freeMemory toggle. Page lookups — and the mapping from blocks back to their parent arenas — stay O(1) via dense indexing tables.

Large allocations that don't fit within a standard page are shunted directly to the underlying arena and live until the GC is destroyed, keeping the hot path simple while covering edge cases.

API

int main(void) {
    int stack_top;
    // false = cache empty pages (faster); true = return to OS (lower RSS)
    if (!gcInit(&stack_top, false)) return 1;

    int *buffer = gcAlloc(sizeof(int) * 1024);
    buffer[0] = 42;

    gcCollect();         // manual collection trigger
    gcDestroy();         // free everything
    return 0;
}

Performance

Benchmarked on an Apple M3 Pro and a low-power Intel N150 with a 16 GB workload. ReMem carries a ~1.39× constant overhead vs raw malloc/free on the M3 Pro — well within acceptable range for the safety and ergonomics it provides, and dramatically ahead of Python-level runtimes.

  • malloc/free: ~2s (M3 Pro) / ~4s (Intel N150)
  • ReMem, pages cached: ~3s / ~19s — 0.95× RSS vs baseline
  • ReMem, pages freed: ~3s / ~40s — 0.94× RSS
  • Python reference: ~38s / ~81s

Disabling page freeing (freeMemory = false) keeps the hot path fast at the cost of slightly higher RSS. On the M3 Pro, RSS actually ends up lower than a bare arena-only approach due to page recycling.

Roadmap

  • Nursery — projected 1.5–5× speedup for short-lived allocation patterns
  • Multithreading — per-thread arenas, lock-free hot path
  • Instrumentation — real-time stats via gcDebugPrintStats() improvements