Mimalloc Cigarette: Losing one week of my life catching a memory leak (Rust)

Garbage Collection vs Manual Memory Management

  • Debate over GC: some see it as essential for complex, shared object graphs; others report spending more time fighting GC (tuning, disabling, pooling) than manual memory would have cost.
  • Latency-sensitive domains (VR, games, trading) are cited as especially painful with GC pauses and unpredictable behavior; Unity’s GC is called out as particularly bad.
  • Counterpoints: modern GCs (e.g., on the JVM) can be nearly pauseless for many workloads; GC problems are often intertwined with other language design choices (type system, JIT strategy, value types, forced heap allocation).
  • Newer systems programmers increasingly prefer automatic resource management; others insist that for systems work, opaque runtimes and non-negotiable GCs are unacceptable.

mimalloc, Thread-Local Allocators, and Rust

  • Core technical issue: mimalloc keeps freed memory tied to the allocating thread and reclaims it lazily. Cross-thread free patterns can look like leaks until the original thread allocates again or mi_collect is called.
  • Rust’s mimalloc crate wires it in as the global allocator but doesn’t expose mi_collect; the lower-level libmimalloc-sys does.
  • This is framed as a design tradeoff: per-thread optimization vs cross-thread behavior. It’s argued this could bite C/C++ too and is fundamentally an architectural problem.

Language and Allocator Design

  • Critique that Rust and C++ hide allocation behind global allocators, discouraging explicit, domain-specific allocator thinking.
  • Zig is praised for explicit allocator passing, trading convenience for control and predictability.
  • Suggestions to design languages more around mmap/munmap and pages are met with skepticism; page sizes and concurrency concerns make higher-level allocators necessary.
  • Embedded and high-performance contexts often avoid dynamic allocation entirely, using bump or arena allocators.

Debugging War Stories and Reliability

  • Multiple anecdotes of long-running, hard-to-reproduce bugs: UI drag-and-drop issues, stale client state in localStorage, JIT miscompilations, uninitialized locals.
  • Emphasis on reproducibility and the scientific method in debugging; warnings against declaring bugs “fixed” without reproduction.
  • Some languages (e.g., D) choose default initialization of locals to avoid entire classes of memory bugs.

Other Side Topics

  • Brief side debate on using floating point for money: some insist on integer cents; others use floats (even single-precision) for modeling/backtesting with controlled rounding.
  • Observations that allocators and OS resource management (memory, filesystems, file descriptors) have GC-like aspects but important differences in visibility and control.