Garbage Collectors Are Scary

Garbage collection emerges as one of the most intricate and error‑prone areas of systems programming, with several contributors sharing real-world stories of elusive memory bugs caused by subtle GC implementation details. Participants contrast tracing collectors, reference counting, and compile‑time ownership schemes (like Rust’s), weighing simplicity, performance, latency, and correctness, especially in multithreaded or real‑time contexts. The thread also touches on how managed runtimes such as Java and .NET transformed software reliability, while acknowledging the complexity, tooling, and design trade‑offs that come with their garbage collectors.

How Hard and “Scary” Garbage Collectors Are

  • Multiple comments stress that writing a correct, concurrent/real‑time GC is among the hardest areas in systems programming, arguably harder than compilers.
  • Others argue GCs aren’t inherently “scary” but demand exhaustive testing and careful design; simple concurrent collectors exist that fit in a few hundred lines.
  • Debugging GC issues is described as mentally exhausting and often traumatic, with people running “GC torture tests” (collect after every allocation) to flush out bugs.

Real-World GC and ABI Bug Stories

  • Several war stories:
    • AAA game with a custom C++ GC: wrong padding (16 vs 12 bytes) caused rare daily crashes and widespread corruption.
    • OCaml FFI bug: misaligned stack vs x86‑64 ABI and AVX alignment assumptions led to rare, unreproducible crashes.
    • Lisp GC missing register roots caused mysterious corruption until fixed.

Reference Counting vs Tracing GC

  • One side likes reference counting for conceptual simplicity, especially in single-thread or ownership-based designs.
  • Others counter:
    • RC turns many reference operations into writes, bloats objects, and still leaks cycles.
    • Decrements can trigger unbounded cascades of frees, so latency is not predictable.
    • To make RC fast, you need complex analyses that erase its simplicity advantage.
  • Several note that compile-time ownership (Rust-style) plus selective RC is powerful but not “free” in complexity.

Designs Around Threads, Actors, and the Kernel

  • A proposed design: no shared mutable state, per-actor heaps, GC or arenas per actor, and deep-copying messages.
  • Replies note this eases GC and latency but conflicts with some high-performance multithreading patterns.

GCs in Existing Systems

  • .NET GC cited as an advanced example; talks and a large book recommended.
  • Game engines often use custom C++ mark/sweep or special heaps to fight fragmentation.
  • A new embeddable GC “Whippet” is mentioned as promising and grant-funded.

Java, Errors, and Ecosystem Tangents

  • Large subthread veers into Java:
    • Debates over whether Java is “scary,” boring, or unfairly maligned.
    • Complaints center on dependency injection, heavy frameworks, memory bloat, and noisy exceptions.
    • Others strongly defend Java’s GC-based safety, error reporting, and production maturity.