Garbage collection for systems programmers (2023)

Atomics, RCU, and “manual GC” patterns

  • Static atomics are criticized as slow, cache-unfriendly, and not a general replacement for GC or locks.
  • RCU is seen as a specialized, efficient pattern: writers make new versions, readers see a consistent snapshot, and reclamation is deferred until readers are done.
  • Some argue RCU is not “really” GC because objects are in well-defined states and often reclaimed quickly; others note it still fits a broad notion of garbage collection (objects live on past obsolescence until safe to free).

GC vs RAII and external resource management

  • Many note GC only solves heap memory, not file handles, sockets, mmaped files, etc.
  • RAII / deterministic destruction (C++, Rust) is praised for unified handling of memory and external resources.
  • Finalizers in GC languages are described as non-deterministic, tied to memory pressure, and risky for external resources; patterns like try-with-resources / using help but have edge cases (e.g., exceptions between allocation and guard).
  • Some GC ecosystems provide additional language features, ownership wrappers, analyzers, or structural typing to approximate RAII, with mixed satisfaction.

Tracing GC vs Reference Counting and manual management

  • Tracing GCs (ZGC, Shenandoah, .NET, Go-style) are argued to beat naive manual management and simple refcounting on throughput, especially with generational and concurrent designs.
  • Others counter that refcounting can be more predictable, deterministic, and have lower footprint, and is preferred in Rust/Swift-like niches.
  • There’s disagreement whether refcounting has lower latency: some say cascading deletions are problematic; others argue pauses are local to a thread, unlike stop-the-world.
  • Tradeoff often framed as: tracing GC = higher throughput + abstraction, worse footprint; refcounting/RAII = better footprint, more programmer effort, more API coupling.

Latency, real-time, and “GC myths”

  • Pro-GC comments claim modern concurrent GCs have sub‑millisecond pauses, often dwarfed by OS pauses, and are “good enough” for most server workloads.
  • Low-latency practitioners (finance, audio, networking, codecs, routing) insist that even 500 µs spikes are unacceptable where budgets are 2–10 µs end‑to‑end; these domains largely reject GC.
  • Some note manual or refcount-based systems also have unpredictable tail latencies (e.g., big destructors, allocator behavior), but defenders say at least pauses are localized.

Arenas, ownership, and abstraction boundaries

  • Several argue most objects fall into clear lifetime buckets (stack, per-request/frame arenas, long-lived pools), making GC overkill; others respond that “medium-lived” and shared objects, async work, and caching quickly break simple arena designs.
  • Manual memory management is criticized for leaking into APIs (e.g., switching to shared ownership breaks signatures), harming modularity.
  • Rust-style ownership is praised for unifying memory and I/O safety but can make some patterns (self-referential structures, certain shared topologies) awkward or impossible without indirection.

Language experiences and tooling

  • Java: modern foreign-memory APIs reduce JNI pain; ZGC/GenZGC reported with very low pauses, though memory overhead and tuning remain concerns.
  • .NET: GC generally liked, but deterministic cleanup (IDisposable, using) is a persistent pain; newer features (analyzers, pooled async/ValueTask) help.
  • Rust: async/await without GC is described as complex (pinning, lifetimes), and some find it a “hellscape” compared to GC’d languages.
  • Nim (defaulting to RC) is cited as a positive example where most code ignores memory details, improving maintainability.

Research and OS-level ideas

  • New research systems (MPL/MaPLe) advertise “provably efficient” parallel GC and automatic granularity control; authors claim strong theoretical guarantees and promising benchmarks.
  • Some imagine OS-level garbage collection integrated with language runtimes, but note this is largely unrealized outside research systems.