HN Debrief

Watching Go's new garbage collector move through the heap

  • Programming
  • Infrastructure
  • Performance
  • Developer Tools

The post visualizes how Go’s garbage collector moves through the heap, contrasting the older collector with the newer page-oriented design so you can see what gets scanned and why. The useful context is that Go does not rely on a classic compacting collector. Its allocator groups same-sized objects into spans built from 8 KiB pages, and large objects live separately. That means small-object fragmentation does not usually block a later large allocation the way people often imagine.

If you run Go at large heap sizes, the operational question is less "does it compact" and more "how do size classes, page locality, and VM settings affect memory retention and translation overhead." Watch for cases where long-lived objects pin pages, and benchmark huge page settings instead of inheriting old blanket advice to disable them.

Discussion mood

Positive on the article’s visuals and educational value, but mildly frustrated that it ends just as the practical implications get interesting. The comments were mostly curious and technical, with the strongest energy around allocator behavior, huge pages, and real-world memory retention rather than the GC animation itself.

Key insights

  1. 01

    Size classes prevent the scary fragmentation case

    Go’s allocator avoids the classic "small objects block a big allocation" failure mode by separating objects into size classes and placing them in different spans. That changes fragmentation from an existential allocation problem into a utilization problem inside each class, which is much easier for the runtime to manage.

    When diagnosing Go memory issues, do not assume you need compaction to fix them. First check whether the pressure is actually stranded memory inside a size class or pinned pages from long-lived objects.

      Attribution:
    • jerf #1
  2. 02

    Huge pages are part of the performance story

    Once allocation is spread across a large virtual address space, translation overhead becomes real. The argument here is that bigger pages, whether via Transparent Huge Pages on Linux or superpages on FreeBSD, can materially reduce page-table and TLB pressure, and that Linux’s default posture leaves performance on the table more often than people admit.

    If your Go service carries large heaps, add huge page settings to your tuning checklist. Measure them on your workload instead of assuming the distro default is the right answer.

      Attribution:
    • jeffbee #1 #2
    • toast0 #1
  3. 03

    The Redis anti-THP advice was workload-specific

    The case against Transparent Huge Pages was pinned on Redis forking and then dirtying memory across its address space, which forces expensive copy-on-write splitting of huge pages. That is a bad interaction between one workload pattern and the kernel, not proof that huge pages are broadly harmful. The follow-on point is sharper: garbage collectors can trigger similar pain if their mark bits live inside objects and force writes across many pages. Separate bitmap pages avoid that and improve cache behavior.

    Treat anti-THP guidance as a workload claim, not a universal rule. If you build runtimes, allocators, or memory-heavy services, inspect whether metadata writes are scattering across the heap and defeating the VM.

      Attribution:
    • jeffbee #1
    • matheusmoreira #1
  4. 04

    Copying data can free pinned pages sooner

    Manually moving objects into a new slice is not busywork if the old placement keeps a page alive. A small amount of copying can let Go drop memory that would otherwise stay resident because one surviving object sits in the wrong spot.

    If you see a Go process hold on to memory after logically discarding data, look for slice and object layouts that pin spans. A deliberate copy can be the cheapest fix.

      Attribution:
    • okzgn #1

Against the grain

  1. 01

    Page tracking itself may add overhead

    The skepticism here is that if the objects being scanned are already clustered on the same page, extra machinery to manage pages and object tracking can become overhead rather than a win. That is a useful check on the article’s framing because page-aware GC techniques are not free just because they are more sophisticated.

    Do not assume a more page-centric collector always pays off for your workload. Look at scan density and metadata costs before copying the design into another runtime or allocator.

      Attribution:
    • extra-AI #1

In plain english

8 KiB
Eight kibibytes, or 8,192 bytes, a binary unit of memory size.
allocator
The part of a runtime or library responsible for handing out and reclaiming blocks of memory.
bitmap pages
Dedicated memory pages that store compact bit-level metadata, such as mark bits for a garbage collector, instead of storing that metadata inside each object.
copy-on-write
A memory optimization where copied memory pages are only duplicated when one process writes to them.
GC
Garbage collector, the part of a language runtime that automatically finds and reclaims memory no longer in use.
heap
The area of memory where a program allocates objects dynamically while it runs.
size class
A bucket of allocation sizes where requested object sizes are rounded up so similarly sized objects can be managed together.
span
In Go’s allocator, a contiguous chunk of memory pages used to hold objects of a particular size class.
superpages
Larger-than-normal memory pages used by an operating system to reduce address-translation overhead.
TLB
Translation Lookaside Buffer, a small processor cache that stores recent virtual-to-physical address translations.
Transparent Huge Pages
A Linux feature that automatically uses larger memory pages when possible to reduce translation overhead.
virtual address space
The range of memory addresses a program can use, which the operating system maps onto physical RAM as needed.

Reference links

Talks and videos

Papers on large pages