Session

Green Tea GC: The Insight Behind Go's New Garbage Collector

Green Tea's insight is elegant: scan spans, not objects. But how do you actually implement that? What data structures track which objects are marked vs. scanned? Why does the ownership protocol use three states? And how did span-based scanning unlock SIMD optimizations that were impossible before?

This talk dissects Green Tea's implementation: the inline mark bits structure, the FIFO span queues, the ownership protocol that prevents duplicate work, and the AVX-512 SIMD kernels in Go 1.26 that use a cryptographic instruction (VGF2P8AFFINEQB) for bitmap expansion. I've read the actual runtime code and understand why each design decision was made.


Main idea: Green Tea required new data structures to batch objects by span. The 128-byte 'spanInlineMarkBits' structure stores mark/scan state inline at the end of each 8KB span. FIFO queues (not LIFO) let spans accumulate marks before scanning. An ownership protocol prevents duplicate work. And the regular data layout enabled SIMD acceleration in Go 1.26 using AVX-512 instructions originally designed for AES cryptography.

Questions this talk answers:
- Why 63 bytes for marks/scans? An 8KB span with 8-byte objects could hold ~1000 objects. But most size classes are larger. 63 bytes × 8 bits = 504 bits covers typical cases while keeping the structure at 128 bytes (two cache lines).

- Why FIFO queues instead of LIFO? LIFO (stack) would scan spans immediately after adding them—potentially with only one marked object. FIFO lets spans sit longer, accumulating more marks. When finally scanned, you process 10 objects in one cache-friendly pass instead of 10 separate passes.

- How does the ownership protocol work? Three states: unowned, one-mark, many-marks. When you discover a pointer, you atomically set its mark bit and try to acquire the span. If you get it, you enqueue the span. If someone else owns it, you just set the bit—they'll scan your object when they process the span. The one-mark state enables a fast path: skip bitset operations and scan the single object directly.

- How does SIMD help? Mark bits are 1 per object. Pointer scanning needs 1 bit per word (8 bytes). A 48-byte object needs its 1 mark bit expanded to 6 bits. The VGF2P8AFFINEQB instruction does 8×8 bit matrix multiplication—one instruction expands marks for an entire span. This instruction exists for AES; the Go team repurposed it.

- When does SIMD lose? Setup overhead matters. Dense spans (many marked objects) benefit from SIMD. Sparse spans (few marked objects) are faster with scalar iteration. The runtime tracks density and chooses dynamically.

Attendees will understand the data structures well enough to read 'mgcmark_greenteagc.go' themselves, know why each design decision was made (FIFO over LIFO, ownership states, dense vs. sparse paths), and see how architectural decisions cascade: span-based scanning enabled regular data layouts, which enabled SIMD, which the old object-centric GC couldn't use.

This talk is proposed af advanced level. Attendees should be comfortable with atomic operations, cache behavior, and reading Go runtime code. If needed, I'm open to adjusting the depth to benefit the conference.

Alex Rios

Principal Engineer @Memed

Curitiba, Brazil

Actions

Please note that Sessionize is not responsible for the accuracy or validity of the data provided by speakers. If you suspect this profile to be fake or spam, please let us know.

Jump to top