Blog
Isolating heaps as threads isolate data
D already treats ordinary variables as thread-local.
std.concurrency then pushes you toward mailboxes:
copy, immutable, maybe a move.
That is an actor story, told with TLS instead of a second language.
The collector never got the memo.
There is still one process-wide heap, and when any thread collects,
every registered thread stops—including the
@nogc audio callback you promised would never allocate.
Detach the realtime thread if you want a hard guarantee.
After thread_detachThis() the collector will not scan it—
and that thread must never touch GC memory again.
You bought a C island. You did not buy idiomatic D on that core.
What “tgc” is for
We prototyped an opt-in factory named tgc (thread garbage collection; some of us have been saying “realtime GC” in conversation, which is a side-name only). It does not replace the default conservative collector. You ask for it:
./app --DRT-gcopt=gc:tgc
Each attached thread gets its own arena.
When Heap A collects, only Thread A’s stack, TLS, and blocks are in play.
No thread_suspendAll for that cycle.
Sibling GC threads keep running.
Detached @nogc threads never registered in the first place.
The picture that sells it
Think of a small studio app: a present loop that must hold 60 fps, an audio callback that must not hitch, and a decode worker that does allocate. Today, decode’s collection can still stop the shell. With tgc, decode collects locally. The window keeps presenting.
What you pay
Per-thread heaps waste RAM relative to one packed global pool. Thread 1 can sit on free pages Thread 2 still needs from the OS. Moving a buffer without copying means a remote free queue on the owning thread—Thread 2 must not splice Thread 1’s free lists. Huge frames (4K video) still want an explicit shared region, which is Phase 2, not v1.
Phase 2 is a many-to-many sketch: attach workers only to the regions they need, so collecting Region Beta does not pause a worker that never joined it. Transitive coupling can still cascade. The docs article goes into that honestly.
Not the only GC in flight
SymGC
(Steven Schveighoffer / Symmetry Investments; gc:sdc)
is a clean-slate collector aimed at allocation throughput, the global
alloc lock, and a modern layout.
We Need a New GC
from DConf ’24 is the public talk.
That work might become a future default.
tgc is a narrower experiment: pause isolation for mixed GC /
@nogc processes. Complementary axes, not a turf war.
Where to look
We submitted the prototype upstream on 2 August 2026:
dlang/dmd#23514.
Rainer already flagged real limits (immutable sharing, header size,
linear findBlock, remote-free assumptions).
Those belong in review, not in this essay.
- News: Thread-local GC proposed upstream
- Docs: Thread-local garbage collection (tgc) for D
- Prototype branch
feature/tgc - Forum post
Treat v1 as design review and measurement, not a production realtime guarantee. If you already pass messages and keep the shell off the worker heap, this is the GC half of that architecture.