HN
Today

Watching Go's new garbage collector move through the heap

This article offers a deep technical dive into Go's Green Tea garbage collector, introduced in Go 1.25/1.26, showcasing its performance enhancements, especially regarding cache efficiency. Through practical code examples and perf profiling, it meticulously compares Go's non-moving GC behavior to C#'s, revealing significant speedups. Crucially, it highlights Go's inherent challenge with memory fragmentation that stems from its non-compacting design, a topic often debated by performance-conscious developers on HN.

49
Score
1
Comments
#2
Highest Rank
2h
on Front Page
First Seen
Jul 27, 7:00 PM
Last Seen
Jul 27, 8:00 PM
Rank Over Time
22

The Lowdown

The article meticulously explores Go's new Green Tea garbage collector, now the default in Go 1.26, and its implications for memory management and performance. Using detailed code examples in Go and C#, it provides a visual and analytical comparison of how each language handles object allocation and garbage collection, particularly focusing on memory layout and cache efficiency.

  • Go's Allocation Strategy: Go's allocator groups objects of similar sizes into contiguous 8KiB 'spans,' a design principle shared with allocators like tcmalloc. The article demonstrates this visually, showing how Go places same-sized objects adjacent to each other.
  • Non-Moving GC: A key characteristic highlighted is Go's non-moving garbage collector; objects retain their memory addresses even after GC runs, a fact visually confirmed through heap dumps before and after collection.
  • Green Tea's Improvement: The new Green Tea GC optimizes the 'mark' phase by intelligently scanning memory spans for objects and queuing future spans, rather than indiscriminately following every pointer. This change targets improved cache friendliness.
  • Performance Benchmarking with perf: The article employs perf to benchmark the old and new Go GCs across 'packed' and 'scattered' data structures, measuring cache-references and cache-misses.
  • L1 Cache Efficiency: Initial perf results for L3 cache were misleading. By switching to bare metal and analyzing L1-dcache events and Misses Per Kilo Instructions (MPKI), the author concretely demonstrates Green Tea's significant reduction in L1 cache misses and overall faster execution times, validating its cache-friendly design.
  • Go's Fragmentation Vulnerability: Despite Green Tea's advancements, Go's non-moving GC inherently leads to memory fragmentation. An experiment shows that freeing 90% of objects in Go fails to significantly reduce HeapInuse because the remaining objects cannot be moved to compact the heap.
  • C# as a Contrast: In contrast, a similar experiment in C# (which uses a compacting GC) successfully reclaims and consolidates freed memory, showcasing its ability to mitigate fragmentation.
  • Manual Compaction (Go): The article illustrates that, in specific scenarios, developers can manually 'compact' Go's heap by copying live objects to new, contiguous memory regions, albeit this is not an automated GC behavior.

The article effectively demonstrates Green Tea's tangible performance benefits, particularly in optimizing cache utilization. However, it equally emphasizes that Go's fundamental choice of a non-moving garbage collector continues to leave it susceptible to memory fragmentation, a trade-off that distinguishes it from languages with compacting GCs like C#.