Opt-in thread-local GC (tgc): per-thread heaps without global STW

Richard (Rikki) Andrew Cattermole richard at cattermole.co.nz
Mon Aug 3 07:55:55 UTC 2026


On 03/08/2026 6:36 PM, Ryan Johnson wrote:
> Hi all,
> 
> I've been thinking about something awkward in how D handles memory and 
> threads.
> 
> In D, threads mostly keep their own data by default, and std.concurrency 
> already nudges you toward message-passing instead of sharing everything. 
> That feels a lot like little independent workers talking to each other.
> 
> But the garbage collector still acts like one big shared junk drawer for 
> the whole program. When any thread needs a cleanup, the GC freezes every 
> registered thread for a moment — even threads you carefully wrote as 
> @nogc so they could stay smooth and realtime.

Yes, without going into write barriers, this is the primary solution to 
the problem.

The secondary solution is to go concurrent, fork/snapshot.
Basically throw Copy On Write at the MMU level on and go read the old pages.

The current GC only supports fork and StW.

> So I prototyped an optional collector called tgc (thread garbage 
> collection). Think of it as “each thread gets its own mini heap and 
> cleans up its own mess.” I might call that idea a “realtime GC,” but I'm 
> using "TGC" or "tgc" in usage notes.
> 
> You turn it on like this:
> 
>    ./app --DRT-gcopt=gc:tgc
> 
> What it tries to do:
> - Give each thread its own heap
> - Let a thread collect garbage without pausing the other threads
> - Leave the normal default GC alone unless you ask for tgc

- Thread unsafe

> First version is deliberately careful: prefer copying data or sending 
> immutable messages between threads. If you hand a block of memory from 
> one thread to another, the owning thread still cleans it up later. Fancy 
> “shared regions between only some threads” is planned for later, not in 
> this first cut.

Immutable is only useful here if that memory is in read only memory 
allocated by loader.
In other words, global non-TLS memory.

Copying isn't a notion here either, you would need to allocate it using 
the destination threads GC instance. It would need to be a deep copy not 
a shallow copy.

I do want to be very clear on this, message passing is not provide 
thread safety. It relies on language features to be safe.

- Ownership transfer system
- Guarding by mutex
- Immutable

We only have the last, so right now message passing is for all intents 
and purposes an unsafe practice in D. Which is not good enough.

> Links:
> - Upstream PR: #23514
> - Longer explanation: https://dlang-supplemental.github.io/docs/docs/ 
> blog/thread-local-gc-tgc.html
> - Short news note: https://dlang-supplemental.github.io/docs/docs/news/ 
> tgc-upstream-pr.html
> 
> Important: this is not “replace D’s default GC.” It’s an opt-in path for 
> apps that care about pauses. Past forum discussions worried that built- 
> in thread-local heaps get messy with `shared` / `immutable`; making this 
> pluggable and optional keeps that risk small.

It is not thread safe. It is inherently a major risk.
Nothing can utilize it and be thread safe (whilst sticking to GC 
memory), therefore not mergable.

> I’d love feedback on the idea, what’s too limited in v1, and whether 
> this should become a formal DIP. Comment on the PR or reply here.
> 
> Thanks,
> Ryan / dlang-supplemental

Another design I came up with years ago was a graduation.

It comes with the realization that the problem inherent to scanners is 
one of a many to many relationship.

- Number of blocks to scan in.
- Number of blocks to scan for.

You can't decrease both, but you can decrease one of them based upon 
where you do it.

Have a thread local scanner and heap.
Once the stack, TLS, and heap reachable from those two isn't reached 
anymore you move that block to the global heap.

The global scanner then looks at all blocks of memory in program, scans 
for only the blocks it thinks *could* be free.

The global scanner still has to do one of the approaches I described above.

Nice and thread safe. But will take longer to collect I expect.



More information about the Digitalmars-d mailing list