<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Go: Under the Hood</title><link>https://golang.design/under-the-hood/en/</link><description>Recent content on Go: Under the Hood</description><generator>Hugo</generator><language>en</language><atom:link href="https://golang.design/under-the-hood/en/index.xml" rel="self" type="application/rss+xml"/><item><title>Preface</title><link>https://golang.design/under-the-hood/en/preface/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/preface/</guid><description>&lt;h1 id="preface"&gt;Preface&lt;/h1&gt;
&lt;p&gt;The Go language has a history of more than a decade since it first appeared in 2009.
Looking across the history of most programming languages, what is surprising is that over the dozen or so years Go has evolved,
the language itself has not changed all that much, and Go users have been able to keep writing applications that remain backward compatible.
From the standpoint of language design, Go was built from the very beginning around principles such as low cost, high concurrency, and simplicity, and it is hard not to be curious about the implementation mechanisms and the concrete working principles that sit behind that simple design.
This book is one that discusses the technical principles in the Go source code and the course of their evolution.&lt;/p&gt;</description></item><item><title>How to Read This Book</title><link>https://golang.design/under-the-hood/en/how-to-read/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/how-to-read/</guid><description>&lt;h1 id="how-to-read-this-book"&gt;How to Read This Book&lt;/h1&gt;
&lt;p&gt;A reader once told the author that this book is hard going. They had studied Go and used it for a few years, yet when they hit the chapters on scheduling, stealing, and memory, they could still only talk in the abstract. That feedback is sincere, and the author accepts it. Part of the depth this book aims for comes from decades of accumulated work in systems, concurrency, and compilation, and the slope really is steep on first contact. But steep does not mean the only option is to grind through it. What a book can offer is a few paths that make the slope gentler. This page is about how to walk those paths.&lt;/p&gt;</description></item><item><title>1.1 The Evolution of Programming Languages</title><link>https://golang.design/under-the-hood/en/part1overview/ch01intro/history/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch01intro/history/</guid><description>&lt;h1 id="11-the-evolution-of-programming-languages"&gt;1.1 The Evolution of Programming Languages&lt;/h1&gt;
&lt;p&gt;To understand why Go turned out the way it did, why it is so restrained, so obsessed with compilation speed, so concerned with concurrency, we first have to look at the language landscape it was born into, and at whose pain it set out to solve. Go was not designed in a vacuum. It is the response of a group of people who spent their careers writing systems software, a response to their long-standing dissatisfaction with the mainstream languages of the time. Understanding this background gives a unified starting point for all the trade-offs the rest of this book examines, in the scheduler, the memory model, and generics.&lt;/p&gt;</description></item><item><title>1.2 An Overview of the Go Language</title><link>https://golang.design/under-the-hood/en/part1overview/ch01intro/go/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch01intro/go/</guid><description>&lt;h1 id="12-an-overview-of-the-go-language"&gt;1.2 An Overview of the Go Language&lt;/h1&gt;
&lt;p&gt;This section builds a skeleton for the whole book. It is not a syntax manual; Go&amp;rsquo;s syntax is explained clearly in any introductory book, and repeating it would serve no purpose.
What we want to do is first establish a &lt;strong&gt;bird&amp;rsquo;s-eye view of the whole&lt;/strong&gt;: which layers make up Go, which &lt;strong&gt;distinctive&lt;/strong&gt; design decisions it carries,
and where in this book each of those decisions is developed. Once you have read this section, you can dive into any later chapter without losing your way.&lt;/p&gt;</description></item><item><title>1.3 Communicating Sequential Processes</title><link>https://golang.design/under-the-hood/en/part1overview/ch01intro/csp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch01intro/csp/</guid><description>&lt;h1 id="13-communicating-sequential-processes"&gt;1.3 Communicating Sequential Processes&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;This section comes with an online talk: &lt;a href="https://www.youtube.com/watch?v=Z8ZpWVuEx8c"&gt;YouTube&lt;/a&gt;, &lt;a href="https://changkun.de/s/csp/"&gt;Google Slides&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The intellectual source of Go&amp;rsquo;s concurrency model is &lt;strong&gt;Communicating Sequential Processes&lt;/strong&gt; (CSP), which Hoare proposed in CACM in 1978. This section traces that lineage from the perspective of the history of ideas, because it explains why goroutines and channels look the way they do today. The implementation details of channels and select (the ring buffer in hchan, the pairing of &lt;code&gt;gopark&lt;/code&gt; and &lt;code&gt;goready&lt;/code&gt;, the two-round locking in &lt;code&gt;selectgo&lt;/code&gt;) are left for &lt;a href="../../../part3concurrency/ch10chan/readme"&gt;Chapter 10&lt;/a&gt;. Here we are concerned with &amp;ldquo;why CSP&amp;rdquo;, and with how that choice has shaped the appearance of Go programs.&lt;/p&gt;</description></item><item><title>2.1 The Plan 9 Assembly Language</title><link>https://golang.design/under-the-hood/en/part1overview/ch02asm/asm/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch02asm/asm/</guid><description>&lt;h1 id="21-the-plan-9-assembly-language"&gt;2.1 The Plan 9 Assembly Language&lt;/h1&gt;
&lt;p&gt;Read the source of the Go runtime long enough, and sooner or later you run into code that looks
like assembly yet not quite like any assembly you are familiar with. That is Go&amp;rsquo;s
&lt;strong&gt;Plan 9 style assembly&lt;/strong&gt;. We will keep returning to it as we dissect the scheduler, stack
switching, and atomic operations: &lt;code&gt;gogo&lt;/code&gt;, &lt;code&gt;mcall&lt;/code&gt;, &lt;code&gt;morestack&lt;/code&gt;, and &lt;code&gt;asyncPreempt&lt;/code&gt; are all assembly
routines. This section explains what it is, why it exists, and the few key concepts you need in
order to read it. We do not aim to teach the reader to write Plan 9 assembly, which is the subject
of another book; we aim to turn it into a &lt;strong&gt;reading vocabulary&lt;/strong&gt;: when a later section mentions some
assembly routine, the reader knows what kind of abstraction layer it lives in and what each symbol
points to.&lt;/p&gt;</description></item><item><title>2.2 Stack Frames and Symbols in Assembly</title><link>https://golang.design/under-the-hood/en/part1overview/ch02asm/frame/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch02asm/frame/</guid><description>&lt;h1 id="22-stack-frames-and-symbols-in-assembly"&gt;2.2 Stack Frames and Symbols in Assembly&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././asm"&gt;2.1&lt;/a&gt; gave the pseudo-registers and addressing syntax of Plan 9 assembly, which is about &amp;ldquo;how to write one line of assembly&amp;rdquo;. This section raises our view to a complete routine: how a hand-written assembly function declares its own symbol with &lt;code&gt;TEXT ·name(SB)&lt;/code&gt;, how it states its stack frame size with &lt;code&gt;$framesize-argsize&lt;/code&gt;, and what &lt;code&gt;NOSPLIT&lt;/code&gt; means. We will match these conventions point by point against three real routines in the runtime (&lt;code&gt;Cas&lt;/code&gt;, &lt;code&gt;gogo&lt;/code&gt;, &lt;code&gt;morestack&lt;/code&gt;), and once you finish reading, the assembly symbols in the chapters on the scheduler and stack management turn from gibberish into readable, on-the-spot operations.&lt;/p&gt;</description></item><item><title>2.3 Calling Convention and the Register ABI</title><link>https://golang.design/under-the-hood/en/part1overview/ch02asm/callconv/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch02asm/callconv/</guid><description>&lt;h1 id="23-calling-convention-and-the-register-abi"&gt;2.3 Calling Convention and the Register ABI&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;The register names, stack-frame layout, and prologue code in this text use amd64 as the example.
Other architectures (arm64, riscv64, and so on) share the same structure but differ in register names; you can
cross-reference the &amp;ldquo;Architecture specifics&amp;rdquo; section of &lt;code&gt;src/cmd/compile/abi-internal&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A single function call, at the machine level, has to answer a string of concrete questions: where do the arguments go, where does the return value go, who is responsible for saving which registers, how is the stack frame laid out, where is the return address pushed. Pinning down the answers to these questions is the calling convention, often also called the ABI (application binary interface). The ABI is not a piece of code but a &lt;strong&gt;contract&lt;/strong&gt;: the code generated by the compiler, the hand-written Plan 9 assembly (&lt;a href=".././asm"&gt;2.1&lt;/a&gt;), and the low-level routines inside the runtime are written independently of one another, yet they have to mesh exactly at the moment of the call. Once the contract is fixed, all three sides arrange their data according to it, and none of them needs to know the internal details of the others.&lt;/p&gt;</description></item><item><title>2.4 Argument Passing and Stack Frame Layout</title><link>https://golang.design/under-the-hood/en/part1overview/ch02asm/args/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch02asm/args/</guid><description>&lt;h1 id="24-argument-passing-and-stack-frame-layout"&gt;2.4 Argument Passing and Stack Frame Layout&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././callconv"&gt;2.3&lt;/a&gt; laid out the division of labor between the two ABIs and the recursive algorithm for assigning arguments. That was the &amp;ldquo;rule&amp;rdquo;. This section grounds the rule in a concrete example: given a signature that mixes scalars and arrays, how exactly are the arguments arranged in the stack frame, why does a register argument still reserve a spill slot on the stack, and how does the stack growth check that nearly every function pays for in its prologue hitch a ride on preemption. Finally we return to the overall question of &amp;ldquo;why a custom ABI&amp;rdquo; and combine these two sections into a complete answer.&lt;/p&gt;</description></item><item><title>3.1 Starting from the `go` Command</title><link>https://golang.design/under-the-hood/en/part1overview/ch03life/cmd/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch03life/cmd/</guid><description>&lt;h1 id="31-starting-from-the-go-command"&gt;3.1 Starting from the &lt;code&gt;go&lt;/code&gt; Command&lt;/h1&gt;
&lt;p&gt;The life cycle of a Go program begins with running the &lt;code&gt;go&lt;/code&gt; command. The &lt;code&gt;go build&lt;/code&gt;, &lt;code&gt;go test&lt;/code&gt;,
and &lt;code&gt;go run&lt;/code&gt; that readers type every day look like they merely &amp;ldquo;turn source into a binary,&amp;rdquo; but
behind them hides a fact that is often misunderstood: &lt;code&gt;go&lt;/code&gt; itself is not the compiler. It is a
&lt;strong&gt;build orchestrator&lt;/strong&gt;, responsible for breaking a single build into many individual steps,
arranging their ordering and parallelism, and then invoking the real tools one by one: the
compiler &lt;code&gt;compile&lt;/code&gt; (&lt;a href=".././compile"&gt;3.2&lt;/a&gt;), the assembler &lt;code&gt;asm&lt;/code&gt;, and the linker &lt;code&gt;link&lt;/code&gt;
(&lt;a href=".././link"&gt;3.4&lt;/a&gt;). This section first makes this orchestration relationship clear, as it is the
master outline for the sections that follow: once you understand how &lt;code&gt;go&lt;/code&gt; decomposes a build into
a graph and how it uses a content-addressed cache to avoid duplicate work, then turning to the
details of compilation and linking gives you a frame to stand on.&lt;/p&gt;</description></item><item><title>3.2 The Go Compilation Pipeline</title><link>https://golang.design/under-the-hood/en/part1overview/ch03life/compile/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch03life/compile/</guid><description>&lt;h1 id="32-the-go-compilation-pipeline"&gt;3.2 The Go Compilation Pipeline&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././cmd"&gt;3.1&lt;/a&gt; explained that the real work behind &lt;code&gt;go build&lt;/code&gt; is carried out by two programs, &lt;code&gt;compile&lt;/code&gt; and &lt;code&gt;link&lt;/code&gt;. This section zooms in on &lt;code&gt;compile&lt;/code&gt; and traces the full journey from a single &lt;code&gt;.go&lt;/code&gt; source file to a single &lt;code&gt;.o&lt;/code&gt; object file: what each stage receives, what it produces, and why the work is cut up this way. This section is a &lt;strong&gt;panorama&lt;/strong&gt; of the compilation pipeline. The inner workings of each stage (how the grammar is designed, what algorithm type checking uses, the optimization rules of SSA) are left to &lt;a href="../../../part5toolchain/ch15compile/readme"&gt;Chapter 15&lt;/a&gt; to unfold one by one. Here we only string them into a single line and point out two threads that run through all of it.&lt;/p&gt;</description></item><item><title>3.3 Bootstrapping the Language</title><link>https://golang.design/under-the-hood/en/part1overview/ch03life/bootstrap/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch03life/bootstrap/</guid><description>&lt;h1 id="33-bootstrapping-the-language"&gt;3.3 Bootstrapping the Language&lt;/h1&gt;
&lt;p&gt;One question sounds like a paradox: Go&amp;rsquo;s compiler, assembler, linker, and runtime are all written in Go today, so where did the first program capable of compiling Go come from? Without a Go compiler, how do you compile a Go compiler? This is &lt;strong&gt;bootstrapping&lt;/strong&gt;. It is both the classic chicken-and-egg dilemma and a piece of engineering in the history of the Go toolchain that can be retold precisely. This section answers three things: how this egg was first hatched; how, after bootstrapping, the chain for building a new version of Go works, and why the demands it places on the bootstrap version keep rising year over year; and finally, why a language that &amp;ldquo;implements itself with itself&amp;rdquo; deserves to be taken seriously.&lt;/p&gt;</description></item><item><title>3.4 Module Linking</title><link>https://golang.design/under-the-hood/en/part1overview/ch03life/link/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch03life/link/</guid><description>&lt;h1 id="34-module-linking"&gt;3.4 Module Linking&lt;/h1&gt;
&lt;p&gt;The compiler (&lt;a href=".././compile"&gt;3.2&lt;/a&gt;) turns each package into an object file, but an object file cannot run on its own. The object files still reference one another&amp;rsquo;s functions and variables, addresses are not yet fixed, and the runtime support is still missing. Assembling these fragments into a complete program that can be loaded and executed is the job of the &lt;strong&gt;linker&lt;/strong&gt; (&lt;code&gt;cmd/link&lt;/code&gt;, usually invoked by &lt;code&gt;go build&lt;/code&gt; as &lt;code&gt;go tool link&lt;/code&gt;). This section looks at what the linker does, and at a few choices Go makes around linking that together explain why a Go program is so often a self-contained file that &amp;ldquo;just runs once you copy it over.&amp;rdquo;&lt;/p&gt;</description></item><item><title>3.5 Bootstrapping a Go Program</title><link>https://golang.design/under-the-hood/en/part1overview/ch03life/boot/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch03life/boot/</guid><description>&lt;h1 id="35-bootstrapping-a-go-program"&gt;3.5 Bootstrapping a Go Program&lt;/h1&gt;
&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; function the reader writes is not the program&amp;rsquo;s true first instruction. When the
operating system hands control to a Go executable, what starts running is the runtime: it has
to lay out the execution stack on the main thread, bind thread-local storage, measure the CPU
core count and the physical page size of memory, wake up the memory allocator, the garbage
collector, and the scheduler one by one, and only then create the goroutine that carries &lt;code&gt;main&lt;/code&gt;
and hand it to the scheduling loop to run. In other words, a Go binary carries within it a
miniature operating system (&lt;a href="../../ch01intro/go"&gt;1.2&lt;/a&gt;), one that starts itself up ahead of user
code. This section walks the bootstrap chain from end to end, from the operating system&amp;rsquo;s entry
symbol to the moment the first goroutine is scheduled, so we can see clearly what happens
&amp;ldquo;before &lt;code&gt;main&lt;/code&gt;.&amp;rdquo;&lt;/p&gt;</description></item><item><title>3.6 The Life and Death of the Main Goroutine</title><link>https://golang.design/under-the-hood/en/part1overview/ch03life/main/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part1overview/ch03life/main/</guid><description>&lt;h1 id="36-the-life-and-death-of-the-main-goroutine"&gt;3.6 The Life and Death of the Main Goroutine&lt;/h1&gt;
&lt;p&gt;In &lt;a href=".././boot"&gt;3.5&lt;/a&gt;, once &lt;code&gt;schedinit&lt;/code&gt; has assembled the runtime&amp;rsquo;s foundations, it does not call &lt;code&gt;runtime.main&lt;/code&gt; directly. Instead it pushes that function&amp;rsquo;s entry address onto the stack, hands it to &lt;code&gt;newproc&lt;/code&gt; to fabricate the first Goroutine, and then lets &lt;code&gt;mstart&lt;/code&gt; start the scheduling loop and pick this Goroutine out to run. The details of scheduling are left for &lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/"&gt;9 Scheduler&lt;/a&gt;. This section trains the camera on a single moment: &lt;strong&gt;the first Goroutine is already running, and it is about to execute &lt;code&gt;runtime.main&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>4.1 The Runtime Type System</title><link>https://golang.design/under-the-hood/en/part2lang/ch04type/type/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch04type/type/</guid><description>&lt;h1 id="41-the-runtime-type-system"&gt;4.1 The Runtime Type System&lt;/h1&gt;
&lt;p&gt;Go is a statically typed language, and type checking happens at compile time. Yet Go still keeps a substantial amount of &lt;strong&gt;runtime type information&lt;/strong&gt; (RTTI), and it is precisely this that supports interfaces (&lt;a href=".././interface"&gt;4.2&lt;/a&gt;), type assertions, type switches, reflection, and the garbage collector&amp;rsquo;s precise identification of pointers. This section answers a seemingly simple question: of the type machinery that exists at compile time, what survives into the runtime, in what form is it kept, and what capabilities does it underpin. Once you understand the small structure called the &lt;strong&gt;type descriptor&lt;/strong&gt; in this section, the interface (&lt;a href=".././interface"&gt;4.2&lt;/a&gt;), reflection, and precise GC (&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/"&gt;13&lt;/a&gt;) all gain a common footing.&lt;/p&gt;</description></item><item><title>4.2 Interfaces</title><link>https://golang.design/under-the-hood/en/part2lang/ch04type/interface/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch04type/interface/</guid><description>&lt;h1 id="42-interfaces"&gt;4.2 Interfaces&lt;/h1&gt;
&lt;p&gt;Interfaces are the soul of Go&amp;rsquo;s type system. They decouple behavior from implementation, and they do it in an unusual way: structural, implicit satisfaction, unlike most mainstream languages. This section looks at how interfaces are represented at runtime, how methods are dispatched dynamically, how type assertions are realized, and where this design sits within the broader lineage of polymorphism. Following the approach of the previous sections, the structs given below are &lt;strong&gt;trimmed-down sketches&lt;/strong&gt;: they keep only the fields relevant to the design, with comments explaining why each one exists. For the full definitions, compare against &lt;code&gt;runtime/runtime2.go&lt;/code&gt;, &lt;code&gt;internal/abi/iface.go&lt;/code&gt;, and &lt;code&gt;runtime/iface.go&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>4.3 Type Aliases</title><link>https://golang.design/under-the-hood/en/part2lang/ch04type/alias/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch04type/alias/</guid><description>&lt;h1 id="43-type-aliases"&gt;4.3 Type Aliases&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;type A = B&lt;/code&gt; (a type alias) and &lt;code&gt;type A B&lt;/code&gt; (defining a new type) differ by a single equals sign, yet the
semantics are fundamentally different. The former merely gives a new name to an existing type; the latter
creates a brand-new type with its own independent identity. The distinction looks minor, but it pulls on the
whole set of rules governing type equality, method sets, and assignability (&lt;a href=".././type"&gt;4.1&lt;/a&gt;), and it also
pulls on a question Go has always cared about: when a body of code is no longer maintained by its original
author yet still has to evolve without breaking compatibility, how should a type migrate from one package to
another. This section first makes the semantics of aliases and defined types clear, then explains why aliases
were introduced in Go 1.9, and finally looks at the generic capability they gained in Go 1.24.&lt;/p&gt;</description></item><item><title>5.1 Arrays and Slices</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/slice/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/slice/</guid><description>&lt;h1 id="51-arrays-and-slices"&gt;5.1 Arrays and Slices&lt;/h1&gt;
&lt;p&gt;Arrays and slices are the two most basic sequence types in Go. They look similar, yet their memory models differ, and grasping this one point explains in a single stroke all the &amp;ldquo;surprises&amp;rdquo; of append and the traps of slice aliasing. Both share a single theme: a small &lt;strong&gt;header&lt;/strong&gt; describing a stretch of contiguous backing memory. The differences lie entirely in what the header holds and who owns that memory. This section first lays out the layout clearly, then starts from the classic abstraction of the &amp;ldquo;dynamic array&amp;rdquo; to see how Go&amp;rsquo;s &lt;code&gt;append&lt;/code&gt; achieves amortized &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;math xmlns="http://www.w3.org/1998/Math/MathML"&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy="false"&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy="false"&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding="application/x-tex"&gt;O(1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class="katex-html" aria-hidden="true"&gt;&lt;span class="base"&gt;&lt;span class="strut" style="height:1em;vertical-align:-0.25em;"&gt;&lt;/span&gt;&lt;span class="mord mathnormal" style="margin-right:0.02778em;"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, and finally lands on aliasing and cross-language comparison, the corners we run into day to day. Strings, though they share the same origin as slices, are immutable and form a category of their own; we leave them to &lt;a href=".././string"&gt;5.2&lt;/a&gt; for dedicated discussion.&lt;/p&gt;</description></item><item><title>5.2 Strings and Zero-Copy Conversion</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/string/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/string/</guid><description>&lt;h1 id="52-strings-and-zero-copy-conversion"&gt;5.2 Strings and Zero-Copy Conversion&lt;/h1&gt;
&lt;p&gt;Strings share their origin with slices: in the runtime both are &amp;ldquo;a header plus memory living elsewhere&amp;rdquo; (for the layout, see &lt;a href="https://golang.design/under-the-hood/en/part2lang/ch05data/slice/#511-%e4%b8%89%e7%a7%8d%e5%86%85%e5%ad%98%e5%b8%83%e5%b1%80"&gt;5.1.1&lt;/a&gt;). But a string is &lt;strong&gt;read-only and immutable&lt;/strong&gt;, which makes it its own category. Immutability buys us sharing and copy-free use, and it brings one direct cost: converting between &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;[]byte&lt;/code&gt; copies the bytes by default. This section opens up that copy, looks at the cases where the compiler can elide it, then turns to the manual zero-copy tools Go 1.20 provides and the safety contract that comes with them.&lt;/p&gt;</description></item><item><title>5.3 Hash Tables: Principles and Security</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/map/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/map/</guid><description>&lt;h1 id="53-hash-tables-principles-and-security"&gt;5.3 Hash Tables: Principles and Security&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;map&lt;/code&gt; underwent a rare, complete rewrite in 2024 alongside Go 1.24,
moving from the classic bucketed hash table it had used for fourteen years to an implementation based on Swiss Tables. This section first clarifies the general principles of hash tables
and the attack-and-defense around them, leaving the full story of the rewrite to &lt;a href=".././swisstable"&gt;5.4&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;map&lt;/code&gt; is one of only two generic containers Go provides (the other being slice). It is implemented by the runtime with the compiler assisting in layout,
and at its core it is a hash table. When the reader writes &lt;code&gt;m[k]&lt;/code&gt;, the compiler translates it into calls to the &lt;code&gt;runtime.mapaccess&lt;/code&gt;
and &lt;code&gt;runtime.mapassign&lt;/code&gt; family of functions; the real storage, lookup, and growth all happen inside the
&lt;code&gt;internal/runtime/maps&lt;/code&gt; package. This section first lays out the general principles of hash tables and the attack-and-defense around them, to ground the next section where we drop down to Go&amp;rsquo;s own
two generations of implementation (the classic bucketed design from 1.0 through 1.23, and the Swiss Table design from 1.24 onward). Only by understanding the trade-offs here
can we see why the latter was worth a rewrite that cut to the bone.&lt;/p&gt;</description></item><item><title>5.4 Swiss Table and the Go 1.24 Implementation</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/swisstable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/swisstable/</guid><description>&lt;h1 id="54-swiss-table-and-the-go-124-implementation"&gt;5.4 Swiss Table and the Go 1.24 Implementation&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././map"&gt;5.3&lt;/a&gt; laid out the general principles of hash tables and the attack-and-defense around them: the two routes for handling collisions, and the defense against hash flooding. This section comes down to Go&amp;rsquo;s own two generations of implementation. We first open up Swiss Table, a modern open-addressing design, then look at how Go 1.24 brought it to ground and what it replaced in the process, then derive from the implementation two language rules that follow from it, and finally place Go within the larger picture of the various hash tables out there.&lt;/p&gt;</description></item><item><title>6.1 Function Calls</title><link>https://golang.design/under-the-hood/en/part2lang/ch06func/func/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch06func/func/</guid><description>&lt;h1 id="61-function-calls"&gt;6.1 Function Calls&lt;/h1&gt;
&lt;p&gt;Functions are first-class citizens in Go: they can be assigned, passed, returned, and they can capture
outer variables to become closures. Behind this lie two implementation questions: how a function value
(a closure) is represented in memory, and how a single function call passes arguments and returns values
at the lowest level. The latter also hides a quiet but sweeping change introduced in Go 1.17: passing
arguments in registers instead of on the stack. This section explains both thoroughly, and at the seam
between them points out a key fact, the very fact that welds &amp;ldquo;what a closure is&amp;rdquo; and &amp;ldquo;how a call happens&amp;rdquo;
into one and the same thing.&lt;/p&gt;</description></item><item><title>6.2 Deferred Statements</title><link>https://golang.design/under-the-hood/en/part2lang/ch06func/defer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch06func/defer/</guid><description>&lt;h1 id="62-deferred-statements"&gt;6.2 Deferred Statements&lt;/h1&gt;
&lt;p&gt;The deferred statement &lt;code&gt;defer&lt;/code&gt; did not exist in the earliest Go designs; it was added later as a separate feature, with Robert Griesemer writing the language specification [Griesemer, 2009] and Ken Thompson producing the earliest implementation [Thompson, 2009]. Its semantics read very short: a &lt;code&gt;defer&lt;/code&gt;-red call runs when the enclosing function returns, when a panic occurs, or when &lt;code&gt;runtime.Goexit&lt;/code&gt; is called. Intuitively this looks like a purely compile-time feature, similar to C++&amp;rsquo;s RAII (automatic destruction when leaving a scope); the compiler would seem to only need to &amp;ldquo;move&amp;rdquo; the deferred call to the end of the function, with no runtime cost.&lt;/p&gt;</description></item><item><title>6.3 The panic and recover Builtins</title><link>https://golang.design/under-the-hood/en/part2lang/ch06func/panic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch06func/panic/</guid><description>&lt;h1 id="63-the-panic-and-recover-builtins"&gt;6.3 The panic and recover Builtins&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;defer&lt;/code&gt; (&lt;a href=".././defer"&gt;6.2&lt;/a&gt;) has already settled the question of &amp;ldquo;what to do when a function exits,&amp;rdquo; leaving open the question of &amp;ldquo;what happens when a function is interrupted abnormally.&amp;rdquo; The pair of builtins &lt;code&gt;panic&lt;/code&gt; and &lt;code&gt;recover&lt;/code&gt; answers exactly this: the former interrupts the current normal control flow and begins unwinding up the call stack, while the latter catches it mid-unwind. This section first makes their semantics clear, then comes down to the go1.26 runtime implementation of &lt;code&gt;gopanic&lt;/code&gt; and &lt;code&gt;gorecover&lt;/code&gt;, and finally returns to a more pressing question: what panic should really be taken to be, and why Go did not make it into an exception mechanism like the one in C++ or Java.&lt;/p&gt;</description></item><item><title>7.1 The Evolution of the Problem</title><link>https://golang.design/under-the-hood/en/part2lang/ch07errors/value/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch07errors/value/</guid><description>&lt;h1 id="71-the-evolution-of-the-problem"&gt;7.1 The Evolution of the Problem&lt;/h1&gt;
&lt;p&gt;In &lt;a href="../../ch06func/panic"&gt;6.3&lt;/a&gt; we already drew the dividing line: how to handle errors is one of the
fundamental choices in language design. The exception camp (C++, Java, Python) uses &lt;code&gt;try/catch&lt;/code&gt; to
pull the error path out of the normal logic, keeping the main line clean, at the cost of making the
error path implicit, capable of being thrown from any call site. The value camp (Go, Rust, and C&amp;rsquo;s
return-code tradition) passes errors explicitly as ordinary return values: verbose, but every error
path is spelled out in black and white with nowhere to hide. Go chose the value camp, reserving a
lightweight &lt;code&gt;panic&lt;/code&gt;/&lt;code&gt;recover&lt;/code&gt; only for &amp;ldquo;true exceptions.&amp;rdquo; What this section is about is what happened
after that choice landed: how the proposition of &amp;ldquo;errors as values&amp;rdquo; itself evolved, from a string you
could only print into a tree that a program can interrogate layer by layer, asking &amp;ldquo;are you really
that error?&amp;rdquo;&lt;/p&gt;</description></item><item><title>7.2 Inspecting Error Values</title><link>https://golang.design/under-the-hood/en/part2lang/ch07errors/inspect/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch07errors/inspect/</guid><description>&lt;h1 id="72-inspecting-error-values"&gt;7.2 Inspecting Error Values&lt;/h1&gt;
&lt;p&gt;Once an error propagates up a call chain, the code that handles it and the code that produced it
are often separated by many layers. This raises a plain but thorny question: given an &lt;code&gt;error&lt;/code&gt; that
has been passed up through layer after layer, how does the caller decide &amp;ldquo;is this actually some
particular error&amp;rdquo;, and how does it retrieve the specific error value that originally carried the
context? This section answers exactly that, along with the conventions Go has set down for it in
the &lt;code&gt;errors&lt;/code&gt; package.&lt;/p&gt;</description></item><item><title>7.3 Error Format and Context</title><link>https://golang.design/under-the-hood/en/part2lang/ch07errors/context/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch07errors/context/</guid><description>&lt;h1 id="73-error-format-and-context"&gt;7.3 Error Format and Context&lt;/h1&gt;
&lt;p&gt;A good error does not merely say &amp;ldquo;something went wrong.&amp;rdquo; It tells a person what was being done, on account of what, and what went wrong. The evolution of the problem (&lt;a href=".././value"&gt;7.1&lt;/a&gt;) and value inspection (&lt;a href=".././inspect"&gt;7.2&lt;/a&gt;) gave us the mechanisms for propagating and examining errors. This section discusses the engineering practice that sits on top of those mechanisms: how the text of an error should be written, how context accumulates layer by layer along the call chain, and how stack traces and structured logs can be added on demand when human-written words are not enough. Running through all of it is one overall tendency Go has regarding error information: human-written semantic context is preferable to machine-collected stack traces.&lt;/p&gt;</description></item><item><title>7.4 Error Semantics</title><link>https://golang.design/under-the-hood/en/part2lang/ch07errors/semantics/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch07errors/semantics/</guid><description>&lt;h1 id="74-error-semantics"&gt;7.4 Error Semantics&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././inspect"&gt;7.2&lt;/a&gt; and &lt;a href=".././context"&gt;7.3&lt;/a&gt; stood on the caller&amp;rsquo;s side of an error and worked out how, once
you hold an &lt;code&gt;error&lt;/code&gt;, to inspect it along the chain and how to layer context onto it. This section turns the
viewpoint to the other side, standing with the library author and asking a question that comes before
inspection: when a package wants to expose a failure to the outside world, what &lt;strong&gt;form&lt;/strong&gt; should it give that
error? Should it export a comparable value, export a type with fields, or export nothing at all?&lt;/p&gt;</description></item><item><title>7.5 The Future of Error Handling</title><link>https://golang.design/under-the-hood/en/part2lang/ch07errors/future/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch07errors/future/</guid><description>&lt;h1 id="75-the-future-of-error-handling"&gt;7.5 The Future of Error Handling&lt;/h1&gt;
&lt;p&gt;In the preceding sections we saw the plainness of the &lt;code&gt;error&lt;/code&gt; interface, &lt;code&gt;%w&lt;/code&gt; wrapping, and the inspection of error chains. By this point the reader probably carries an unspoken question: those three lines of &lt;code&gt;if err != nil&lt;/code&gt; boilerplate, spread year after year across every Go program, is there really no way to get rid of them? The question is not a lonely one. From the go2 draft of 2018 to a single conclusion in 2025, the Go team weighed it back and forth for seven years, proposing several syntaxes such as &lt;code&gt;check&lt;/code&gt;/&lt;code&gt;handle&lt;/code&gt;, &lt;code&gt;try&lt;/code&gt;, and &lt;code&gt;?&lt;/code&gt;, and then withdrawing them one by one. This section places that path of failed syntax side by side with another, quietly successful path of library evolution, and lays out the judgment the Go team finally arrived at: for the foreseeable future, error handling will not receive any dedicated syntax.&lt;/p&gt;</description></item><item><title>8.1 The Evolution of Generics Design</title><link>https://golang.design/under-the-hood/en/part2lang/ch08generics/history/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch08generics/history/</guid><description>&lt;h1 id="81-the-evolution-of-generics-design"&gt;8.1 The Evolution of Generics Design&lt;/h1&gt;
&lt;p&gt;Generics is the feature Go waited longest for, argued about most fiercely, and that best embodies its design philosophy. From the open-source release in 2009 to its arrival in Go 1.18 in 2022, the thirteen years of hesitation and the eventual choices are themselves a lesson in language design. This section answers three questions: why Go held off on generics for so long, how it finally added them, and how they are implemented underneath. The last question matters most, because Go&amp;rsquo;s implementation copies no existing precedent and instead takes a distinctive middle road, and it is that road that is Go&amp;rsquo;s real answer to the thirteen-year problem. How the design itself evolved along the way (contracts, type sets, several rounds of syntax proposals) is left to &lt;a href=".././future"&gt;8.4&lt;/a&gt;; this section takes only the skeleton.&lt;/p&gt;</description></item><item><title>8.2 Contract-Based Generics</title><link>https://golang.design/under-the-hood/en/part2lang/ch08generics/contracts/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch08generics/contracts/</guid><description>&lt;h1 id="82-contract-based-generics"&gt;8.2 Contract-Based Generics&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;This section has a companion online talk: &lt;a href="https://www.youtube.com/watch?v=E16Y6bI2S08"&gt;on YouTube&lt;/a&gt;,
&lt;a href="https://changkun.de/s/go2generics/"&gt;Google Slides deck&lt;/a&gt;. The deck was recorded in 2019, while the contracts
proposal was still under discussion, and it corroborates this section.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=".././history"&gt;8.1&lt;/a&gt; glossed over the evolution &amp;ldquo;contracts came first, then a turn toward interfaces as constraints&amp;rdquo;
in a single sentence. This section unfolds that sentence: what contracts actually looked like, how much expressive
power they had, and why they were ultimately abandoned. This rejected design is not historical waste; it explains
where today&amp;rsquo;s &lt;code&gt;[T Ordered]&lt;/code&gt; syntax came from, and it illustrates a move that recurs throughout Go&amp;rsquo;s design: first
produce a highly expressive but somewhat complex scheme, then turn back and ask &amp;ldquo;can this be expressed with concepts
we already have&amp;rdquo;, forcing complexity to earn its right to exist.&lt;/p&gt;</description></item><item><title>8.3 Type-Checking Techniques</title><link>https://golang.design/under-the-hood/en/part2lang/ch08generics/checker/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch08generics/checker/</guid><description>&lt;h1 id="83-type-checking-techniques"&gt;8.3 Type-Checking Techniques&lt;/h1&gt;
&lt;p&gt;Generics pose a far harder problem to the type checker than before. The old judgment had only one shape: &amp;ldquo;is this value of this type?&amp;rdquo; With type parameters, the checker now has to answer three new questions: whether a type argument satisfies a constraint, whether an operation like &lt;code&gt;a + b&lt;/code&gt; is valid on an unknown type, and what that unwritten &lt;code&gt;T&lt;/code&gt; actually is when you call &lt;code&gt;Max(3, 5)&lt;/code&gt;. These three concerns correspond to the three topics of this section: type sets, core types, and type inference. They are where the design from &lt;a href=".././history"&gt;8.1&lt;/a&gt; lands as concrete compile-time technique, and they are also a prelude to the front end of &lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch15compile/"&gt;15 The Compiler&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>8.4 The Future of Generics</title><link>https://golang.design/under-the-hood/en/part2lang/ch08generics/future/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch08generics/future/</guid><description>&lt;h1 id="84-the-future-of-generics"&gt;8.4 The Future of Generics&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Generics landed in 1.18 and more than four years have passed. This section no longer dwells on
speculation about &amp;ldquo;what might be.&amp;rdquo; Instead it looks back and takes inventory: which expectations
were met, which were deliberately shelved, and where the tension that runs through it all (the
cost of abstraction) stands today. The author once gave a public talk on Go 2 generics in earlier
years (&lt;a href="https://www.youtube.com/watch?v=E16Y6bI2S08"&gt;YouTube&lt;/a&gt;,
&lt;a href="https://changkun.de/s/go2generics/"&gt;slides&lt;/a&gt;). Most of those predictions can now be checked against
reality, and this section accounts for them along the way.&lt;/p&gt;</description></item><item><title>9.1 The Scheduling Problem and the GMP Model</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/model/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/model/</guid><description>&lt;h1 id="91-the-scheduling-problem-and-the-gmp-model"&gt;9.1 The Scheduling Problem and the GMP Model&lt;/h1&gt;
&lt;p&gt;Write &lt;code&gt;go f()&lt;/code&gt; and a goroutine starts running. Behind that one line sits the most intricate
machine in the Go runtime: the scheduler. It has to answer a question that is not at all
simple: how can tens of thousands of goroutines take turns on a small handful of CPU cores,
running fast while letting the user barely notice it is there. This section first lays out the
problem the scheduler must solve, its overall skeleton, and its place in the larger family of
concurrent runtimes. Later sections then go deep into each component.&lt;/p&gt;</description></item><item><title>9.2 Work-Stealing Scheduling</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/steal/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/steal/</guid><description>&lt;h1 id="92-work-stealing-scheduling"&gt;9.2 Work-Stealing Scheduling&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././model"&gt;9.1&lt;/a&gt; left us a question: each P has its own local queue, so work is bound to be distributed unevenly. Some Ps are overwhelmed while others sit idle. How to spread the load without introducing a central bottleneck is the core difficulty of concurrent scheduling. Go&amp;rsquo;s answer is a design with thirty years of theory behind it, one that recurs throughout the industry: work stealing.&lt;/p&gt;
&lt;p&gt;This section goes a bit deeper than the rest. We first make clear what Go does, then trace back to the scheduling theory behind it (why it is &amp;ldquo;provably good&amp;rdquo;), then look across its different incarnations in systems such as Cilk, Java, and Rust, and finally stop at the questions that remain open.&lt;/p&gt;</description></item><item><title>9.3 The MPG Model and the Units of Concurrent Scheduling</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/mpg/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/mpg/</guid><description>&lt;h1 id="93-the-mpg-model-and-the-units-of-concurrent-scheduling"&gt;9.3 The MPG Model and the Units of Concurrent Scheduling&lt;/h1&gt;
&lt;p&gt;The first question a scheduler must answer is not &amp;ldquo;how to schedule&amp;rdquo; but &amp;ldquo;what to schedule.&amp;rdquo; Go calls the thing being scheduled a goroutine, and carries it on a triple of M, P, and G. Before we get our hands on the scheduling algorithm (from &lt;a href=".././schedule"&gt;9.4&lt;/a&gt; onward), this section settles these three scheduling units: what a goroutine really is within the lineage of computer science, how its running context is encoded, why scheduling itself has to happen on a special g0, what states a goroutine passes through over its life, and how the worker thread M that carries it is parked and unparked. Once these few things are clear, the scheduling algorithms that follow are just &amp;ldquo;moving G around among these units.&amp;rdquo;&lt;/p&gt;</description></item><item><title>9.4 The Scheduling Loop</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/schedule/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/schedule/</guid><description>&lt;h1 id="94-the-scheduling-loop"&gt;9.4 The Scheduling Loop&lt;/h1&gt;
&lt;p&gt;The previous sections laid out the materials: we know what G, M, and P are (&lt;a href=".././mpg"&gt;9.3&lt;/a&gt;), and we know how an M finds work (&lt;a href=".././steal"&gt;9.2&lt;/a&gt;). This section actually sets them spinning, watching how the scheduling loop ceaselessly picks and runs goroutines on a single thread, and how it strikes a balance between &amp;ldquo;letting a single goroutine run a little longer&amp;rdquo; (throughput and locality) and &amp;ldquo;not letting any goroutine starve&amp;rdquo; (fairness).&lt;/p&gt;</description></item><item><title>9.5 Thread Management</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/thread/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/thread/</guid><description>&lt;h1 id="95-thread-management"&gt;9.5 Thread Management&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././model"&gt;9.1&lt;/a&gt; laid down the three-layer GMP structure: G is the user-level unit of execution, P is the scheduling permit and the carrier of local resources, and M is the leg actually borrowed from the operating system. The previous sections dwelt mostly on G and P; this section turns its attention to M, and answers several questions we have kept deferring: what M actually is, where it comes from, why GOMAXPROCS caps P while the thread count is often larger, why a single blocking system call does not drag down the other G alongside it, and what price the runtime pays when a user wants to pin a goroutine to a specific thread (&lt;code&gt;LockOSThread&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>9.6 Signal Handling</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/signal/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/signal/</guid><description>&lt;h1 id="96-signal-handling"&gt;9.6 Signal Handling&lt;/h1&gt;
&lt;p&gt;Operating system signals are asynchronous and low-level: a signal may interrupt any thread at any
moment, and what the signal handler is allowed to do is severely constrained. What Go users want,
on the other hand, is usually to wire a channel to &lt;code&gt;SIGINT&lt;/code&gt; with &lt;code&gt;signal.Notify&lt;/code&gt; and shut down
gracefully when it arrives. What the runtime has to do is build a bridge between these two: turn a
treacherous asynchronous signal into an event a goroutine can consume in peace. Every design choice
on this bridge is governed by one hard constraint: what can be done inside a signal context. Once
you understand this constraint, the rest of this section&amp;rsquo;s mechanics are merely its corollaries.&lt;/p&gt;</description></item><item><title>9.7 Cooperation and Preemption</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/preemption/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/preemption/</guid><description>&lt;h1 id="97-cooperation-and-preemption"&gt;9.7 Cooperation and Preemption&lt;/h1&gt;
&lt;p&gt;In &lt;a href=".././schedule"&gt;9.5 The Scheduling Loop&lt;/a&gt; we left an open question: if some G runs for too long,
how can other G&amp;rsquo;s still get scheduled? The answer cannot avoid an old pair of concepts from
scheduling theory, cooperative versus preemptive. Cooperative scheduling relies on the scheduled
party voluntarily yielding; preemptive scheduling relies on the scheduler interrupting the
scheduled party from the outside.&lt;/p&gt;
&lt;p&gt;The Go runtime has nothing like the hardware interrupt capability of an operating system kernel.
The work-stealing scheduler (&lt;a href=".././steal"&gt;9.2&lt;/a&gt;) is essentially first-come-first-served cooperative
scheduling. How it can still forcibly interrupt a G that refuses to yield, without sacrificing this
premise, is the design this section sets out to make clear. The thread starts from a theoretical
question: by what right can the runtime not stop a goroutine at an arbitrary instruction?&lt;/p&gt;</description></item><item><title>9.8 System Monitoring</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/sysmon/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/sysmon/</guid><description>&lt;h1 id="98-system-monitoring"&gt;9.8 System Monitoring&lt;/h1&gt;
&lt;p&gt;The scheduler&amp;rsquo;s ordinary path was laid out in &lt;a href=".././schedule"&gt;9.4 The Scheduling Loop&lt;/a&gt;: one M binds to one P,
takes a Goroutine off the queue, runs it, then takes the next. This path rests on one premise, that it gets a chance to run at all.
Yet once all the Ps are mired in long system calls, or some Goroutine spins forever and holds a P hostage, ordinary scheduling
seizes up. No one takes the P back, and no one polls the network. Put differently, cooperative logic that runs on a P
cannot deal with the situation where &amp;ldquo;the P itself cannot move.&amp;rdquo;&lt;/p&gt;</description></item><item><title>9.9 The Network Poller</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/poller/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/poller/</guid><description>&lt;h1 id="99-the-network-poller"&gt;9.9 The Network Poller&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Source facts verified against &lt;code&gt;src/runtime/netpoll.go&lt;/code&gt; and its per-platform
implementations (&lt;code&gt;netpoll_epoll.go&lt;/code&gt;, &lt;code&gt;netpoll_kqueue.go&lt;/code&gt;, and so on) and
&lt;code&gt;src/internal/poll/fd_unix.go&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Go&amp;rsquo;s network code looks blocking: &lt;code&gt;conn.Read&lt;/code&gt; simply &amp;ldquo;sits&amp;rdquo; there waiting for data.
But if it truly blocked the operating system thread it runs on, then ten thousand
goroutines waiting on the network would tie up ten thousand threads, and the M:N model
that &lt;a href=".././model"&gt;9.1&lt;/a&gt; worked so hard to build would collapse in an instant. What lets
the blocking style still scale is the network poller (netpoller). Behind it lies a long
history about &amp;ldquo;how to tend a vast number of connections with a handful of threads.&amp;rdquo; This
section first lays out that history and the design axes behind it, then looks at how Go
hides a mature event mechanism inside the runtime so that you write synchronous code and
run event-driven I/O.&lt;/p&gt;</description></item><item><title>9.10 Timers</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/timer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/timer/</guid><description>&lt;h1 id="910-timers"&gt;9.10 Timers&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;time.Sleep&lt;/code&gt;, &lt;code&gt;time.After&lt;/code&gt;, &lt;code&gt;time.Timer&lt;/code&gt;, &lt;code&gt;time.Ticker&lt;/code&gt;, and even &lt;code&gt;SetDeadline&lt;/code&gt; on network reads and writes
all rest on the same timer machinery. It has to answer a question that looks simple but is in fact subtle, a
question about data structures: when thousands of timers exist at once, how do we efficiently know &amp;ldquo;who should
be woken next, and when,&amp;rdquo; without burning a thread to do it. This section starts from that abstract problem,
makes the trade-offs of the various solutions clear, and then lands on Go&amp;rsquo;s choice and how it evolved.&lt;/p&gt;</description></item><item><title>9.11 NUMA Awareness and the Future of the Scheduler</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/numa/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch09sched/numa/</guid><description>&lt;h1 id="911-numa-awareness-and-the-future-of-the-scheduler"&gt;9.11 NUMA Awareness and the Future of the Scheduler&lt;/h1&gt;
&lt;p&gt;The scheduler described in the preceding sections rests on an assumption that was never spelled out: every M reaches memory equally fast, and moving a G between any two Ps costs the same. On a laptop or a single-socket server, that assumption is nearly true. But once you put the program on a large multi-socket server it begins to break, and the more cores there are, the wider the gap. This section is about that crack: where it comes from, why the Go scheduler has looked past it for so long, a NUMA-aware design that was carefully thought through yet never shipped, and how users today work around it.&lt;/p&gt;</description></item><item><title>10.1 Channels and the Engineering of CSP</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/model/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/model/</guid><description>&lt;h1 id="101-channels-and-the-engineering-of-csp"&gt;10.1 Channels and the Engineering of CSP&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;A recorded talk accompanies this section: &lt;a href="https://www.youtube.com/watch?v=d7fFCGGn0Wc"&gt;online on YouTube&lt;/a&gt;,
&lt;a href="https://changkun.de/s/chansrc/"&gt;Google Slides deck&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CSP gives Go a claim: processes do not share state, they coordinate solely by passing messages
(&lt;a href="https://golang.design/under-the-hood/en/part1overview/ch01intro/csp/"&gt;1.3&lt;/a&gt;). This section is concerned with a different question:
for an engineering language to make this claim real, what shape must &amp;ldquo;communication&amp;rdquo; take so that
an ordinary programmer can reach for it and get it right. Go&amp;rsquo;s answer is the channel, a first-class
primitive that is at once synchronization and communication. We begin by laying out its model at the
surface of the language, its type, its send and receive syntax, the two semantics of buffered versus
unbuffered, directional restriction, and nil behavior, building the intuition that the later sections
will need as they descend into the runtime implementation (&lt;a href=".././impl"&gt;10.2&lt;/a&gt;–&lt;a href=".././pattern"&gt;10.7&lt;/a&gt;).&lt;/p&gt;</description></item><item><title>10.2 hchan: The Internal Structure of a Channel</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/impl/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/impl/</guid><description>&lt;h1 id="102-hchan-the-internal-structure-of-a-channel"&gt;10.2 hchan: The Internal Structure of a Channel&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././readme"&gt;10.1&lt;/a&gt; placed channels within the language from the angle of CSP: a channel is an explicit message conduit that fuses &amp;ldquo;communication&amp;rdquo; and &amp;ldquo;synchronization&amp;rdquo; into one. This section takes it apart. At runtime a channel is a struct called &lt;code&gt;hchan&lt;/code&gt;, and its whole secret amounts to a single lock, a ring of buffered storage, plus two wait queues. The structure is small, yet every field exists for a specific design reason. Once you understand these few pieces, the entire logic of sending, receiving, and select that follows (&lt;a href=".././sendrecv"&gt;10.3&lt;/a&gt;–&lt;a href=".././lockfree"&gt;10.6 The Memory Model and the Move Toward Lock-Free&lt;/a&gt;) is just &amp;ldquo;moving data, parking and waking goroutines on top of this one picture.&amp;rdquo;&lt;/p&gt;</description></item><item><title>10.3 Send, Receive, and Direct Handoff</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/sendrecv/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/sendrecv/</guid><description>&lt;h1 id="103-send-receive-and-direct-handoff"&gt;10.3 Send, Receive, and Direct Handoff&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././impl"&gt;10.2&lt;/a&gt; laid out the skeleton of &lt;code&gt;hchan&lt;/code&gt;: a lock, a ring buffer &lt;code&gt;buf&lt;/code&gt;, plus a sender
queue &lt;code&gt;sendq&lt;/code&gt; and a receiver queue &lt;code&gt;recvq&lt;/code&gt;. This section brings the skeleton to life and answers
what actually happens inside the runtime during a single &lt;code&gt;ch &amp;lt;- v&lt;/code&gt; and a single &lt;code&gt;v := &amp;lt;-ch&lt;/code&gt;. Once
you understand this send/receive path, the two most frequently asked properties of a channel, why
an unbuffered channel is a single rendezvous, and why for it a receive happens before the
corresponding send completes (&lt;a href="../../ch11sync/mem"&gt;11.9&lt;/a&gt;), both come down to the same mechanism:
&lt;strong&gt;direct send / receive&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>10.4 The Semantics of Closing</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/close/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/close/</guid><description>&lt;h1 id="104-the-semantics-of-closing"&gt;10.4 The Semantics of Closing&lt;/h1&gt;
&lt;p&gt;In the previous sections, both sending and receiving were &amp;ldquo;one-to-one&amp;rdquo; rendezvous: one send pairs with one receive, and the surplus side blocks and waits. Closing is the only &amp;ldquo;one-to-many&amp;rdquo; operation on a channel. &lt;code&gt;close(ch)&lt;/code&gt; is issued by a single Goroutine, yet in an instant it wakes every receiver currently blocked on the channel and makes every blocked sender panic on the spot. This ability to &amp;ldquo;broadcast once and wake everyone&amp;rdquo; turns closing from a seemingly minor cleanup action into the most commonly used cancellation and wind-down mechanism in Go concurrency. The done channel pattern and &lt;code&gt;context&lt;/code&gt; cancellation (&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/context/"&gt;11.8&lt;/a&gt;) both trace their roots back here.&lt;/p&gt;</description></item><item><title>10.5 The Implementation of select</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/select/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/select/</guid><description>&lt;h1 id="105-the-implementation-of-select"&gt;10.5 The Implementation of select&lt;/h1&gt;
&lt;p&gt;The previous sections covered send and receive on a single channel (&lt;a href=".././sendrecv"&gt;10.3&lt;/a&gt;) in
full. In practice, though, a Goroutine rarely watches just one channel: it wants to react to
&lt;strong&gt;whichever operation becomes ready first&lt;/strong&gt; among several sends and receives, and it also wants
to avoid blocking when &lt;strong&gt;none of them is ready&lt;/strong&gt;. &lt;code&gt;select&lt;/code&gt; exists exactly for this. Its semantics
look simple, yet the implementation has to solve two thorny problems at once: how to choose
&lt;strong&gt;fairly&lt;/strong&gt; when several branches are ready, and how to &lt;strong&gt;avoid deadlock&lt;/strong&gt; when locking several
channels to run a single select. These two concerns shape the entire structure of &lt;code&gt;selectgo&lt;/code&gt;,
and this section is built around them.&lt;/p&gt;</description></item><item><title>10.6 The Memory Model and the Lock-Free Evolution</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/lockfree/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/lockfree/</guid><description>&lt;h1 id="106-the-memory-model-and-the-lock-free-evolution"&gt;10.6 The Memory Model and the Lock-Free Evolution&lt;/h1&gt;
&lt;p&gt;The previous sections took the channel apart down to its parts: the direct handoff in &lt;a href=".././sendrecv"&gt;10.3&lt;/a&gt;
lets the sending and receiving ends pass a value directly, bypassing the ring buffer, and &lt;code&gt;select&lt;/code&gt; in
&lt;a href=".././select"&gt;10.5&lt;/a&gt; makes a random choice among several ready branches. These mechanisms explain how a
channel &amp;ldquo;runs&amp;rdquo;. This section answers two higher-level questions: what &lt;strong&gt;visibility guarantee&lt;/strong&gt; a channel
offers to a concurrent program, and an engineering mystery that is often raised, why a channel is still
&amp;ldquo;a lock plus a queue&amp;rdquo; to this day rather than the supposedly faster lock-free structure. The former reconnects
the channel to the memory model in &lt;a href="../../ch11sync/mem"&gt;11.9&lt;/a&gt;; the latter is a real trade-off about &amp;ldquo;how
correctness and maintainability win out over peak performance&amp;rdquo;.&lt;/p&gt;</description></item><item><title>10.7 Engineering Practice and Cross-Language Comparison</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/pattern/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch10chan/pattern/</guid><description>&lt;h1 id="107-engineering-practice-and-cross-language-comparison"&gt;10.7 Engineering Practice and Cross-Language Comparison&lt;/h1&gt;
&lt;p&gt;The previous sections took the internal structure of a channel, the send and receive paths,
and the implementation of select all the way down. Once we understand the mechanism, a harder
and more engineering-flavored question follows: when should we use a channel, and when should we
not. Go&amp;rsquo;s slogan, &amp;ldquo;Do not communicate by sharing memory; instead, share memory by communicating,&amp;rdquo;
is easily read as &amp;ldquo;any shared state should go through a channel,&amp;rdquo; but that is not what its author
meant. This section reduces that slogan to an actionable rule of thumb, sets it against the lighter
tools in the chapter on synchronization primitives (&lt;a href="../../ch11sync/readme"&gt;Chapter 11&lt;/a&gt;),
and then places Go&amp;rsquo;s choice within the lineage of the CSP family, so we can understand its specific
coordinates in the design space.&lt;/p&gt;</description></item><item><title>11.1 Shared-Memory Synchronization Patterns</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/basic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/basic/</guid><description>&lt;h1 id="111-shared-memory-synchronization-patterns"&gt;11.1 Shared-Memory Synchronization Patterns&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;The fact that programs can be constructed from simpler basic primitives is a strong
guarantee: what these primitives contain stays logically consistent with the rest of the
programming language.
&amp;ndash; C. A. R. Hoare&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The whole difficulty of concurrent programming can be distilled into a single sentence:
multiple units of execution must cooperate over the same shared state, and the order in
which each of them makes progress cannot be predicted. How to make that cooperation both
correct and efficient has, over more than half a century, split into two great traditions.
This chapter is about one of them, shared memory. Before we take apart the concrete
primitives in Go&amp;rsquo;s standard library &lt;code&gt;sync&lt;/code&gt; and &lt;code&gt;sync/atomic&lt;/code&gt;, this section first lays the
two traditions side by side to tell them apart, explains why they are dual to each other,
and then states where Go stands between them. Once you understand this layer of trade-offs,
the sections from &lt;a href=".././mutex"&gt;11.2&lt;/a&gt; through &lt;a href=".././mem"&gt;11.9&lt;/a&gt; are no longer isolated APIs
but the same design philosophy landing on different scenarios.&lt;/p&gt;</description></item><item><title>11.2 Mutex</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mutex/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mutex/</guid><description>&lt;h1 id="112-mutex"&gt;11.2 Mutex&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;sync.Mutex&lt;/code&gt; is the most basic synchronization primitive: it lets only one goroutine enter the
critical section at a time. Beneath that plain interface, it keeps weighing two goals that pull
against each other, &lt;strong&gt;throughput&lt;/strong&gt; (hand the lock to someone as quickly as possible, do not let the
CPU sit idle) and &lt;strong&gt;fairness&lt;/strong&gt; (do not let some unlucky waiter wait in line forever). The two cannot
both be maxed out: handing the lock off in strict arrival order is the fairest, but pays a context
switch on every handoff; letting a just-woken waiter compete freely with whoever is running is the
fastest, but can leave some waiter losing out again and again. This section first lays out the theory
and the hardware foundations of the old problem of mutual exclusion, then looks at how Go&amp;rsquo;s mutex
walks this tightrope.&lt;/p&gt;</description></item><item><title>11.3 Atomic Operations</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/</guid><description>&lt;h1 id="113-atomic-operations"&gt;11.3 Atomic Operations&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;sync/atomic&lt;/code&gt; is the layer of Go&amp;rsquo;s synchronization primitives that sits closest to the hardware.
Higher-level tools such as the mutex (&lt;a href=".././mutex"&gt;11.1&lt;/a&gt;) and channels (&lt;a href="../ch08channel"&gt;8&lt;/a&gt;) are all
built on top of atomic operations internally. It provides &amp;ldquo;indivisible&amp;rdquo; reads, writes, and
read-modify-writes: an atomic operation either happens in full or not at all, and no other goroutine
ever sees it half-finished. But the meaning of atomic operations goes far beyond &amp;ldquo;no tearing.&amp;rdquo; It is
the foundation of lock-free programming, and behind lock-free programming lies a profound theory
about &amp;ldquo;which primitives can do what.&amp;rdquo; That theory is what this section really wants to make clear.&lt;/p&gt;</description></item><item><title>11.4 Condition Variables</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/cond/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/cond/</guid><description>&lt;h1 id="114-condition-variables"&gt;11.4 Condition Variables&lt;/h1&gt;
&lt;p&gt;The mutex (&lt;a href=".././mutex"&gt;11.2&lt;/a&gt;) answers the question of &amp;ldquo;who may enter the critical section.&amp;rdquo; A condition variable answers a different one: &amp;ldquo;a Goroutine has already entered the critical section, but finds it cannot do its work yet; how does it wait until the moment it can, while yielding the critical section to others.&amp;rdquo; The producer and consumer is the most common example. When the queue is full, the producer can neither write nor keep spinning while holding the lock, otherwise the consumer can never acquire the lock to free up space, and both sides deadlock together. The condition variable &lt;code&gt;sync.Cond&lt;/code&gt; offers this way out: let the producer &amp;ldquo;sleep with the lock,&amp;rdquo; atomically hand off the lock and block, and once the consumer frees up space, wake it back up, with the lock back in its hands on waking.&lt;/p&gt;</description></item><item><title>11.5 Wait Groups</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/waitgroup/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/waitgroup/</guid><description>&lt;h1 id="115-wait-groups"&gt;11.5 Wait Groups&lt;/h1&gt;
&lt;p&gt;The mutex (&lt;a href=".././mutex"&gt;11.2&lt;/a&gt;) and the condition variable (&lt;a href=".././cond"&gt;11.4&lt;/a&gt;) from the previous
sections solve the problem of &amp;ldquo;multiple Goroutines contending for the same shared state.&amp;rdquo; This
section turns to &lt;code&gt;sync.WaitGroup&lt;/code&gt;, which solves a different class of problem: one Goroutine spawns
several subtasks, then waits for all of them to finish before continuing. The former is contention,
the latter is rendezvous. This is one of the most common structures in concurrent programming,
called fork-join, and &lt;code&gt;WaitGroup&lt;/code&gt; is exactly the Go standard library&amp;rsquo;s answer to it.&lt;/p&gt;</description></item><item><title>11.6 Object Pool</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/pool/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/pool/</guid><description>&lt;h1 id="116-object-pool"&gt;11.6 Object Pool&lt;/h1&gt;
&lt;p&gt;Allocating and then discarding the same kind of temporary object over and over puts heavy pressure on
the garbage collector (&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/"&gt;13&lt;/a&gt;). &lt;code&gt;sync.Pool&lt;/code&gt; offers a way out: stash a used object
and reuse it next time instead of allocating fresh every time. Its typical use is for temporary objects
like buffers and serializers that are &amp;ldquo;discarded after one use, yet needed again and again&amp;rdquo;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bufPool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bufPool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;().(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// the object you get back may be dirty, so reset it first&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ... use b ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;bufPool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// put it back when done, for others to reuse&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;New&lt;/code&gt; is the only field the user needs to supply: when the pool has no object to hand out, it falls back
to &lt;code&gt;New&lt;/code&gt; to make one. So what &lt;code&gt;Get&lt;/code&gt; returns is either an old object someone just put back, or a new one
freshly made by &lt;code&gt;New&lt;/code&gt;, and the caller has no way, and no need, to tell the two apart. This section first
covers the ancient idea of reusing objects that the pool rests on, then unpacks the three layers it builds
for concurrency and GC: per-P sharding, the victim cache, and cooperation with the runtime&amp;rsquo;s GC.&lt;/p&gt;</description></item><item><title>11.7 Concurrency-Safe Hash Table</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/map/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/map/</guid><description>&lt;h1 id="117-concurrency-safe-hash-table"&gt;11.7 Concurrency-Safe Hash Table&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;sync.Map&lt;/code&gt; went through a complete internal rewrite in Go 1.24: the original
read/dirty two-map design was replaced by a concurrent hash-trie. This section first makes the
origin of each of these two generations of design clear, then places them back into the
solution lineage of concurrent hash tables.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The language&amp;rsquo;s built-in &lt;code&gt;map&lt;/code&gt; is not concurrency-safe. When multiple goroutines read and write the same &lt;code&gt;map&lt;/code&gt; simultaneously without synchronization,
the runtime actively detects the concurrent access and terminates the process with &lt;code&gt;fatal error: concurrent map read and map write&lt;/code&gt;
(&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch05data/map/"&gt;5.2&lt;/a&gt; introduced this detection mechanism; it is unrecoverable, and &lt;code&gt;recover&lt;/code&gt;
cannot intercept it). For services with availability requirements, this is a design question that must be answered head-on: when multiple goroutines need to share
one table, what structure should be used.&lt;/p&gt;</description></item><item><title>11.8 Context</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/context/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/context/</guid><description>&lt;h1 id="118-context"&gt;11.8 Context&lt;/h1&gt;
&lt;p&gt;A request entering a server seldom runs to completion inside a single goroutine. It fans out into
a tree of goroutines: one queries the database, one calls a downstream RPC, one reads the cache,
and each of these spawns smaller units of work in turn. Once the originator of the request no longer
needs the result, say the client has disconnected, or the upstream has already timed out, all the
work still running across that tree becomes pure waste, holding connections, locks, and memory while
no one will ever read what it produces. The problem then becomes: &lt;strong&gt;how do we propagate the signal
&amp;ldquo;stop here&amp;rdquo; from the root of the tree out to every leaf, so each of them can stop on its own.&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>11.9 Memory Consistency Models</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/</guid><description>&lt;h1 id="119-memory-consistency-models"&gt;11.9 Memory Consistency Models&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Go&amp;rsquo;s memory model went through an important revision in 2022 with Go 1.19.
After laying out the current model, this section devotes space to the background of that
revision (see &lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/#1198-the-evolution-of-the-design"&gt;11.9.8&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The reader may have noticed that in the earlier discussion of the Go runtime and compiler we
kept steering clear of one topic: Go&amp;rsquo;s memory model. The avoidance was not without reason. To
explain it properly requires groundwork in concurrency, synchronization primitives, and even
the hardware layer, and only now is that groundwork in place. As the close of this chapter,
and as the book&amp;rsquo;s summary of Go&amp;rsquo;s synchronization primitives and patterns, we take up the
topic here and answer the question still unresolved in the reader&amp;rsquo;s mind: when two Goroutines
read and write the same variable at once, under what conditions is one side&amp;rsquo;s write
guaranteed to be seen by the other.&lt;/p&gt;</description></item><item><title>12.1 Design Principles</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/basic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/basic/</guid><description>&lt;h1 id="121-design-principles"&gt;12.1 Design Principles&lt;/h1&gt;
&lt;p&gt;By now we have seen how a Go program starts up, and how the scheduler spreads goroutines across operating-system threads for execution. The single thing that scheduled code does most often is request memory: every &lt;code&gt;new&lt;/code&gt;, every local variable that escapes to the heap, every slice growth, all funnel into the same entry point, &lt;code&gt;runtime.mallocgc&lt;/code&gt;. This chapter is about the allocator behind that entry point. This section does not yet touch its parts; it answers a question that comes first: what mutually pulling goals must a memory allocator built for Go satisfy, and on which few judgments does it settle them? Once you understand these trade-offs, the structures and paths in the following sections (&lt;a href=".././component"&gt;12.2&lt;/a&gt;–&lt;a href=".././tinyalloc"&gt;12.6&lt;/a&gt;) will all have a clear origin.&lt;/p&gt;</description></item><item><title>12.2 Components</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/component/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/component/</guid><description>&lt;h1 id="122-components"&gt;12.2 Components&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././basic"&gt;12.1&lt;/a&gt; described the allocator as a layered structure that is &amp;ldquo;lock-free on the fast path, locked on the slow path.&amp;rdquo; This section names and locates the few core components of that structure, and grounds them in their actual form in go1.26: what state each component carries, why it is designed the way it is, and how they chain together into a restocking pipeline. Once you have understood these few things, the later allocation paths (&lt;a href=".././largealloc"&gt;12.4&lt;/a&gt;–&lt;a href=".././tinyalloc"&gt;12.6&lt;/a&gt;) are just &amp;ldquo;a walk across this same picture.&amp;rdquo;&lt;/p&gt;</description></item><item><title>12.3 Initialization</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/init/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/init/</guid><description>&lt;h1 id="123-initialization"&gt;12.3 Initialization&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././component"&gt;12.2&lt;/a&gt; broke the allocator down into a few parts: mcache, mcentral, mheap, and arena. But that was a
static picture. These parts do not fall into place on their own; they must be set up once, at the very start of the
program. This section answers the question: when &lt;code&gt;main&lt;/code&gt; has not yet run and the first &lt;code&gt;new&lt;/code&gt; has not yet happened, what
infrastructure does the runtime lay down for the allocator.&lt;/p&gt;</description></item><item><title>12.4 Large Object Allocation</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/largealloc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/largealloc/</guid><description>&lt;h1 id="124-large-object-allocation"&gt;12.4 Large Object Allocation&lt;/h1&gt;
&lt;p&gt;The allocation hierarchy of &lt;a href=".././component"&gt;12.2&lt;/a&gt; was built for objects that are &amp;ldquo;small and frequent&amp;rdquo;: a per-P mcache, a mcentral shared by size class, and a global mheap. These three cache layers collapse the vast majority of allocations into a handful of lock-free bit operations. But this delicate machine carries an implicit premise, that the object is small enough to fit into a size class. Once an object exceeds &lt;code&gt;maxSmallSize&lt;/code&gt; (32768 bytes in go1.26, that is 32KB), it no longer fits into any size class slot, and the whole replenishment chain loses its meaning for it.&lt;/p&gt;</description></item><item><title>12.5 Small Object Allocation</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/smallalloc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/smallalloc/</guid><description>&lt;h1 id="125-small-object-allocation"&gt;12.5 Small Object Allocation&lt;/h1&gt;
&lt;p&gt;Small objects are those whose size falls between 16B and 32KB (in go1.26, &lt;code&gt;maxSmallSize = 32768&lt;/code&gt;). They are the most common kind of allocation in a Go program: a struct, the backing array of a modest slice, the result of a string concatenation, the vast majority land in this range. The path the allocator designs for them is the main stage of the mcache → mcentral → mheap hierarchy from &lt;a href=".././component"&gt;12.2&lt;/a&gt;, and it is where the whole allocator&amp;rsquo;s &amp;ldquo;lock-free fast path&amp;rdquo; design (&lt;a href=".././basic"&gt;12.1&lt;/a&gt;) makes good on its performance promise.&lt;/p&gt;</description></item><item><title>12.6 Tiny Object Allocation</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/tinyalloc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/tinyalloc/</guid><description>&lt;h1 id="126-tiny-object-allocation"&gt;12.6 Tiny Object Allocation&lt;/h1&gt;
&lt;p&gt;The previous two sections walked through the two ends of the allocator. Large objects (&lt;a href=".././largealloc"&gt;12.4&lt;/a&gt;) bypass the cache and ask the mheap for memory by the page directly; small objects (&lt;a href=".././smallalloc"&gt;12.5&lt;/a&gt;) pull an equal-sized slot from the per-P mcache according to their size class. This section fills in the last and least conspicuous category of object, the &lt;strong&gt;tiny object&lt;/strong&gt;: those smaller than 16 bytes and free of pointers. They are extremely numerous and individually tiny, so if each were also given a slot by size class, the waste would be astonishing. Go sets up a dedicated path for them, packing multiple tiny objects &lt;strong&gt;into the same block&lt;/strong&gt;, and trades one simple &amp;ldquo;bump pointer&amp;rdquo; technique for sizable memory savings.&lt;/p&gt;</description></item><item><title>12.7 The Page Allocator</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/pagealloc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/pagealloc/</guid><description>&lt;h1 id="127-the-page-allocator"&gt;12.7 The Page Allocator&lt;/h1&gt;
&lt;p&gt;Beneath mheap (&lt;a href=".././component"&gt;12.2&lt;/a&gt;), the component that answers &amp;ldquo;which pages are free, which are in use&amp;rdquo; is the page allocator. It is the foundation of the entire allocator: when an mcentral runs out of spans it asks mheap for new pages, large objects (&lt;a href=".././largealloc"&gt;12.4&lt;/a&gt;) are requested directly by page, and every page a span occupies is ultimately carved out from here. The page allocator must also return pages that have stayed idle for a long time back to the operating system. These two responsibilities, one tied to the speed of allocation and the other to the resident memory of the process, are exactly the most enduring tension in Go&amp;rsquo;s memory system.&lt;/p&gt;</description></item><item><title>12.8 Memory Statistics</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/mstats/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/mstats/</guid><description>&lt;h1 id="128-memory-statistics"&gt;12.8 Memory Statistics&lt;/h1&gt;
&lt;p&gt;The allocator keeps books while it works. Every time it wholesales a stretch of address space from the operating system, carves out a span, or allocates or sweeps an object, the runtime accumulates the corresponding count into a set of global variables (&lt;code&gt;runtime.memstats&lt;/code&gt;). These books are not a statistical report compiled after the fact; they are a running ledger written down in passing during allocation and reclamation. They serve two ends. Outwardly, they let users and monitoring systems see the memory shape of the process. Inwardly, both &lt;a href="../../ch13gc/pacing"&gt;the GC pacer (13.3)&lt;/a&gt; and &lt;a href=".././pagealloc"&gt;the soft memory limit &lt;code&gt;GOMEMLIMIT&lt;/code&gt; (12.7)&lt;/a&gt; must read these books to decide &amp;ldquo;at what heap size should the next round of reclamation be triggered.&amp;rdquo; In other words, the bookkeeping closes a feedback loop: allocation produces data, data drives decisions, and decisions in turn constrain allocation.&lt;/p&gt;</description></item><item><title>12.9 Past, Present, and Future</title><link>https://golang.design/under-the-hood/en/part4memory/ch12alloc/history/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch12alloc/history/</guid><description>&lt;h1 id="129-past-present-and-future"&gt;12.9 Past, Present, and Future&lt;/h1&gt;
&lt;p&gt;The allocator did not arrive fully formed. It has been polished over and over as Go evolved. Tracing this line of evolution makes clear which trade-offs the current design grew out of, and gives a glimpse of where it is headed. One judgment worth keeping in mind first: nearly every major change to the allocator was not made to make &amp;ldquo;allocation itself faster,&amp;rdquo; but to re-place a stone in the three-way game among allocation speed, memory footprint, and cooperation with the garbage collector. Once this main thread is read, the several rewrites below stop looking like isolated version trivia and become instead the same engineering problem being solved again and again.&lt;/p&gt;</description></item><item><title>13.1 The Basic Idea of Garbage Collection</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/</guid><description>&lt;h1 id="131-the-basic-idea-of-garbage-collection"&gt;13.1 The Basic Idea of Garbage Collection&lt;/h1&gt;
&lt;p&gt;Garbage collection (GC) frees the programmer from manual &lt;code&gt;free&lt;/code&gt;, at the cost that the runtime must decide for itself which memory is still useful and which can be reclaimed. Go&amp;rsquo;s GC treats low latency as its first priority: it would rather give up a little throughput and memory than let stalls (stop-the-world pauses) grow beyond the sub-millisecond range. This section sets up the theoretical coordinates of GC: reachability, mark-sweep, the tricolor abstraction, and where Go sits within the GC design space. The sections that follow are the elaboration of this basic idea.&lt;/p&gt;</description></item><item><title>13.2 Write Barrier Techniques</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/barrier/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/barrier/</guid><description>&lt;h1 id="132-write-barrier-techniques"&gt;13.2 Write Barrier Techniques&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././basic"&gt;13.1&lt;/a&gt; sketched the tricolor abstraction and the outline of concurrent collection: the collector recolors objects from white to grey and from grey to black, driving a &amp;ldquo;grey wavefront&amp;rdquo; that advances monotonically across the object graph, and wherever the wavefront has passed is confirmed live. If the mutator (the user-space code) were to halt while the wavefront advances, the abstraction would be self-consistent and would converge correctly. The trouble is precisely that the mutator does not halt. The fundamental difficulty of concurrent collection is this: the collector traces the object graph while the mutator rewrites it, and the two hold conflicting accounts of one and the same graph.&lt;/p&gt;</description></item><item><title>13.3 Trigger Frequency and the Pacing Algorithm</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/pacing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/pacing/</guid><description>&lt;h1 id="133-trigger-frequency-and-the-pacing-algorithm"&gt;13.3 Trigger Frequency and the Pacing Algorithm&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././barrier"&gt;13.2&lt;/a&gt; explained how the write barrier lets concurrent marking coexist with the mutator, guaranteeing that &amp;ldquo;we can keep allocating even while collection is under way.&amp;rdquo; That leaves a question of timing: when should the next round of GC start? Too late, and the heap has already grown to an unacceptable size; too early, and frequent collection burns CPU for nothing. The answer comes from the &lt;strong&gt;pacer&lt;/strong&gt;, introduced in Go 1.5 and redesigned in 1.18. This section first lays out the full timeline of a GC cycle, then makes clear what kind of feedback controller the pacer is: it must finish marking before the heap reaches its goal, all while the mutator keeps allocating.&lt;/p&gt;</description></item><item><title>13.4 Scan Marking and Mark Assist</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/mark/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/mark/</guid><description>&lt;h1 id="134-scan-marking-and-mark-assist"&gt;13.4 Scan Marking and Mark Assist&lt;/h1&gt;
&lt;p&gt;Marking is the main body of GC&amp;rsquo;s work: starting from the roots (global variables, each goroutine&amp;rsquo;s stack, registers),
it follows pointers and blackens every reachable object (the tricolor abstraction of &lt;a href=".././basic"&gt;13.1&lt;/a&gt;). A naive
implementation would stop the whole world and walk the object graph single-threaded, which is exactly where early Go&amp;rsquo;s
unbearable pauses came from. After go1.5, marking was reshaped into a form where two things hold at once: it advances
&lt;strong&gt;concurrently with the user program&lt;/strong&gt;, and when the user allocates too fast it can &lt;strong&gt;amortize the cost&lt;/strong&gt; onto the
allocator itself. This section answers three questions: how marking unfolds in parallel without the workers stepping on
each other; how, when scanning an object, we know which of its fields are pointers; and what guarantees that marking
will never be left permanently behind while the user allocates and marking chases.&lt;/p&gt;</description></item><item><title>13.5 Sweeping and Bitmaps</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/sweep/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/sweep/</guid><description>&lt;h1 id="135-sweeping-and-bitmaps"&gt;13.5 Sweeping and Bitmaps&lt;/h1&gt;
&lt;p&gt;Once marking (&lt;a href=".././mark"&gt;13.4&lt;/a&gt;) finishes, any object still white is unreachable garbage. Reclaiming the
memory it occupies and handing it back to the allocator is the last step of collection: &lt;strong&gt;sweeping&lt;/strong&gt;. If we
followed the textbook recipe of &amp;ldquo;walk the heap and free dead objects one by one,&amp;rdquo; the cost of sweeping would
be proportional to the number of dead objects, and on a heap with millions of objects that is no small bill.
Go&amp;rsquo;s sweep sidesteps that bill. Three of its design points are worth making clear: sweeping is done by
&lt;strong&gt;flipping a bitmap&lt;/strong&gt; rather than processing objects one at a time; it runs &lt;strong&gt;concurrently&lt;/strong&gt; with the user
program and &lt;strong&gt;lazily&lt;/strong&gt; spreads its cost across the allocation path; and it &lt;strong&gt;does not move objects&lt;/strong&gt;, so it
accepts fragmentation and forgoes compaction. None of these three is accidental. Each corresponds to a
definite engineering trade-off, and this section unpacks them one by one.&lt;/p&gt;</description></item><item><title>13.6 Mark Termination Phase</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/termination/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/termination/</guid><description>&lt;h1 id="136-mark-termination-phase"&gt;13.6 Mark Termination Phase&lt;/h1&gt;
&lt;p&gt;Concurrent marking (&lt;a href=".././mark"&gt;13.4&lt;/a&gt;) carries one nontrivial closing problem: how to &lt;strong&gt;decide that marking is complete&lt;/strong&gt;. In a single-threaded, stop-the-world collector this problem is trivial, the marking thread drains the grey queue and marking is over. But in a concurrent world, &amp;ldquo;my local queue is empty&amp;rdquo; never means &amp;ldquo;there are no grey objects anywhere globally.&amp;rdquo; The instant a worker goroutine drains its own queue, a mutator on another P may happen to execute a pointer write, the write barrier (&lt;a href=".././barrier"&gt;13.2&lt;/a&gt;) then greys a new object and stuffs it into that P&amp;rsquo;s local cache. Deciding termination is, in essence, confirming a &lt;strong&gt;global property&lt;/strong&gt; in a system that has no global lock and whose work is scattered across each P&amp;rsquo;s local cache: the grey set is empty, and no further grey objects will be produced.&lt;/p&gt;</description></item><item><title>13.7 Safe-Point Analysis</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/safe/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/safe/</guid><description>&lt;h1 id="137-safe-point-analysis"&gt;13.7 Safe-Point Analysis&lt;/h1&gt;
&lt;p&gt;The marking phase (&lt;a href=".././mark"&gt;13.4&lt;/a&gt;) must scan a goroutine&amp;rsquo;s stack, find every pointer on the stack that points into the heap, and add them to the grey queue as GC roots. This sounds straightforward, but it hides a premise that is easy to overlook: &lt;strong&gt;is a given machine word on the stack actually a pointer?&lt;/strong&gt; A 64-bit word might be a heap address, or it might be an integer that happens to fall within the range of heap addresses, a half-disassembled floating-point value, or a garbage value that has not been written yet. If we mistake a non-pointer for a pointer, we needlessly hold onto a block of memory that should have been reclaimed; if we miss a pointer and treat it as an integer, we reclaim an object that is still in use, and the latter is fatal memory corruption.&lt;/p&gt;</description></item><item><title>13.8 The Generational Hypothesis and Generational Collection</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/generational/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/generational/</guid><description>&lt;h1 id="138-the-generational-hypothesis-and-generational-collection"&gt;13.8 The Generational Hypothesis and Generational Collection&lt;/h1&gt;
&lt;p&gt;People who have studied the JVM or .NET often ask a pointed question: why does Go &lt;strong&gt;not do generational GC&lt;/strong&gt;? Generational collection is standard equipment in the GCs of mainstream managed runtimes such as Java and .NET, treated as the key to efficient collection, almost to the point of becoming the common sense of &amp;ldquo;this is how a modern GC ought to be.&amp;rdquo; Go pointedly does not adopt it. This section explains the idea of generational collection, its power, and Go&amp;rsquo;s reasons for not taking this road. The answer here deserves care: it is not that &amp;ldquo;the Go team did not think of it,&amp;rdquo; but that the Go team &lt;strong&gt;actually implemented a non-moving generational GC, measured its performance, and in the end gave it up&lt;/strong&gt;. This is a case that powerfully illustrates &amp;ldquo;there is no design that fits all circumstances.&amp;rdquo;&lt;/p&gt;</description></item><item><title>13.9 The Request Hypothesis and the Request-Oriented Collector</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/roc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/roc/</guid><description>&lt;h1 id="139-the-request-hypothesis-and-the-request-oriented-collector"&gt;13.9 The Request Hypothesis and the Request-Oriented Collector&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././generational"&gt;13.8&lt;/a&gt; explained why Go did not adopt the generational hypothesis. The reader may go on to ask: did Go ever try a different &amp;ldquo;object lifetime hypothesis&amp;rdquo;? It did. This section is about an experiment the Go team took seriously and ultimately abandoned, the Request-Oriented Collector (ROC). We discuss it not because it made it into Go, but because an abandoned design often reveals where the constraints lie better than a successful one. ROC is like a proof done wrong: the spot where it goes wrong marks exactly the boundary in Go&amp;rsquo;s GC design space that cannot be crossed.&lt;/p&gt;</description></item><item><title>13.10 Finalizers</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/finalizer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/finalizer/</guid><description>&lt;h1 id="1310-finalizers"&gt;13.10 Finalizers&lt;/h1&gt;
&lt;p&gt;The usual storyline of garbage collection ends at &lt;a href=".././sweep"&gt;sweeping (13.5)&lt;/a&gt;: marking finds the live objects, and sweeping returns the slots of dead objects to the allocator. But there is a class of object that wants to say one last word before it dies. It wraps a non-memory resource, a file descriptor, an mmap region, a handle allocated on the C side, and when the Go-side wrapper object becomes unreachable, the underlying resource ought to be released along with it. Garbage collection only understands memory, though, and has no idea that a descriptor needs to be &lt;code&gt;close&lt;/code&gt;d. The finalizer is the hook designed for exactly this gap: you register a function for an object, and when garbage collection decides the object is unreachable, the runtime does not free it immediately but first calls that function.&lt;/p&gt;</description></item><item><title>13.11 Past, Present, and Future</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/history/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/history/</guid><description>&lt;h1 id="1311-past-present-and-future"&gt;13.11 Past, Present, and Future&lt;/h1&gt;
&lt;p&gt;Having read the previous ten sections, the reader now holds the present state of each part of Go&amp;rsquo;s garbage collector: tri-color marking (&lt;a href=".././basic"&gt;13.1&lt;/a&gt;),
the hybrid write barrier (&lt;a href=".././barrier"&gt;13.2&lt;/a&gt;), the pacer (&lt;a href=".././pacing"&gt;13.3&lt;/a&gt;), and sweeping and reclamation (&lt;a href=".././sweep"&gt;13.5&lt;/a&gt;).
This section takes a different angle: it places these parts back on a timeline and watches how, step by step, they grew into their present shape.&lt;/p&gt;
&lt;p&gt;The evolution of the collector reads like a curve that converges steadily in one direction. From Go 1.0 to today, pause times have dropped by roughly two
orders of magnitude, and along the way one constant theme runs through it all: every change serves the goal of completing collection without disturbing user code.
Once that theme is understood, the many schemes below, both those adopted and those abandoned, can all be measured against the same ruler.&lt;/p&gt;</description></item><item><title>13.12 A Unified Theory of Garbage Collection</title><link>https://golang.design/under-the-hood/en/part4memory/ch13gc/unifiedgc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch13gc/unifiedgc/</guid><description>&lt;h1 id="1312-a-unified-theory-of-garbage-collection"&gt;13.12 A Unified Theory of Garbage Collection&lt;/h1&gt;
&lt;p&gt;Having read through this chapter, we have seen Go&amp;rsquo;s concurrent mark-and-sweep, its hybrid write barrier, and its pacer, and we have set them against other schools of thought such as the generational hypothesis and request-oriented collection. The algorithms come in many flavors, and by this point the reader may have a question building up: beyond the fact that they all &amp;ldquo;do garbage collection,&amp;rdquo; is there a common thread that places them inside a single framework?&lt;/p&gt;</description></item><item><title>14.1 Design of Contiguous Stacks</title><link>https://golang.design/under-the-hood/en/part4memory/ch14stack/design/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch14stack/design/</guid><description>&lt;h1 id="141-design-of-contiguous-stacks"&gt;14.1 Design of Contiguous Stacks&lt;/h1&gt;
&lt;p&gt;Every goroutine carries an execution stack. It holds the local variables, arguments, and return addresses of function calls, and it is the physical medium that lets a program be &amp;ldquo;currently executing&amp;rdquo;. In the C programs the reader is familiar with, this stack is provided by the operating system thread, its size fixed once at thread creation (&lt;code&gt;ulimit -s&lt;/code&gt; defaults are often 8MB) and unchanged thereafter. Go took a different road: a goroutine&amp;rsquo;s stack is not a thread stack but a segment of memory that the runtime allocates on the heap, manages itself, and can resize, starting at just 2KB.&lt;/p&gt;</description></item><item><title>14.2 Stack Allocation and Caching</title><link>https://golang.design/under-the-hood/en/part4memory/ch14stack/alloc/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch14stack/alloc/</guid><description>&lt;h1 id="142-stack-allocation-and-caching"&gt;14.2 Stack Allocation and Caching&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././design"&gt;14.1&lt;/a&gt; located the execution stack as a contiguous range of memory &lt;code&gt;[lo, hi)&lt;/code&gt;: it is managed by the runtime and ultimately lives on the heap, so the moment a Goroutine starts, someone has to carve out this range of addresses for it. The questions follow immediately: who carves it? how large? and once Goroutines are created and destroyed over and over, if these two- or three-kilobyte chunks of memory had to be requested directly from the operating system or the global heap every time, the cost of locks and system calls would crush the scheduler at once.&lt;/p&gt;</description></item><item><title>14.3 Stack Growth</title><link>https://golang.design/under-the-hood/en/part4memory/ch14stack/grow/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch14stack/grow/</guid><description>&lt;h1 id="143-stack-growth"&gt;14.3 Stack Growth&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././readme"&gt;14.1&lt;/a&gt; laid out the reasons Go chose contiguous stacks: a stack starts at just 2KB, and on overflow it swaps in a new stack twice as large and copies the entire old stack across. This section answers only one of the questions involved: how the runtime knows, at the &amp;ldquo;right moment,&amp;rdquo; that a stack is about to fill up, and how it hands control all the way over to the code responsible for the growth. The details of the stack copy itself are left to &lt;a href=".././copy"&gt;14.4&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>14.4 Stack Copying and Pointer Adjustment</title><link>https://golang.design/under-the-hood/en/part4memory/ch14stack/copy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch14stack/copy/</guid><description>&lt;h1 id="144-stack-copying-and-pointer-adjustment"&gt;14.4 Stack Copying and Pointer Adjustment&lt;/h1&gt;
&lt;p&gt;The cost of contiguous stacks is concentrated in one place: when a goroutine&amp;rsquo;s stack overflows, the runtime allocates a new stack twice the size, moves the entire old stack over, and then frees the old stack. The moving step looks like nothing more than a single &lt;code&gt;memmove&lt;/code&gt;, copying the bytes of &lt;code&gt;[old.lo, old.hi)&lt;/code&gt; into &lt;code&gt;[new.lo, new.hi)&lt;/code&gt;. If it really were just copying bytes, a problem would arise: variables on the stack may hold pointers into the stack itself, for example a local variable that has taken the address of another local. After the bytes are moved verbatim to a new address, the values of these pointers are unchanged, still pointing at locations in the old stack, and the old stack is about to be reclaimed. The moment the copy finishes, they become dangling pointers.&lt;/p&gt;</description></item><item><title>14.5 Stack Shrinking and Evolution</title><link>https://golang.design/under-the-hood/en/part4memory/ch14stack/shrink/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part4memory/ch14stack/shrink/</guid><description>&lt;h1 id="145-stack-shrinking-and-evolution"&gt;14.5 Stack Shrinking and Evolution&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././copy"&gt;14.4&lt;/a&gt; was about the stack &amp;ldquo;growing up&amp;rdquo;: when a function prologue finds the stack
nearly exhausted, the runtime copies the whole stack onto a larger block of memory, and the stack
pointer shifts along with it. This is a one-directional force driven by execution itself, and it
only ever makes the stack larger. Yet a goroutine&amp;rsquo;s stack depth is not monotonic. A recursion may
descend very deep, then return layer by layer back to a shallow point; the stack it actually needs
has long since shrunk back, but the large stack expanded for that deep recursion is still held in
its name. With growth but no return, every goroutine&amp;rsquo;s stack would eventually settle at its
historical deepest point. For a program that may hold millions of goroutines, this bill is
unbearable.&lt;/p&gt;</description></item><item><title>15.1 Lexing and Grammar</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/parse/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/parse/</guid><description>&lt;h1 id="151-lexing-and-grammar"&gt;15.1 Lexing and Grammar&lt;/h1&gt;
&lt;p&gt;The first stop of compilation is turning source text into a structured &lt;strong&gt;abstract syntax tree&lt;/strong&gt; (AST). This takes
&lt;strong&gt;lexical analysis&lt;/strong&gt; (slicing a character stream into tokens) and &lt;strong&gt;syntactic analysis&lt;/strong&gt; (organizing tokens into a tree
according to the grammar). &lt;a href="https://golang.design/under-the-hood/en/part1overview/ch03life/compile/"&gt;3.2&lt;/a&gt; surveyed the whole pipeline from above; this
section looks only at its front end, and at why Go&amp;rsquo;s grammar was designed to be so &amp;ldquo;easy to parse&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The package that carries out these two steps is a self-contained part of the compiler, &lt;code&gt;cmd/compile/internal/syntax&lt;/code&gt;. It
is built from two instruments: the &lt;strong&gt;scanner&lt;/strong&gt; reads characters and emits a token stream; the &lt;strong&gt;parser&lt;/strong&gt; consumes tokens
in a &lt;strong&gt;recursive descent&lt;/strong&gt; fashion and builds the syntax tree. The package&amp;rsquo;s own comments even note with some pride that
several of its files, &lt;code&gt;scanner.go&lt;/code&gt;, &lt;code&gt;source.go&lt;/code&gt;, and &lt;code&gt;tokens.go&lt;/code&gt;, do not depend on the rest of the compiler and can be
compiled on their own into a standalone library. The reason lexing and grammar can be carved out this cleanly lies in the
simplicity of the Go grammar itself.&lt;/p&gt;</description></item><item><title>15.2 Intermediate Representation</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/ssa/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/ssa/</guid><description>&lt;h1 id="152-intermediate-representation"&gt;15.2 Intermediate Representation&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././parse"&gt;15.1&lt;/a&gt; turned source code into a syntax tree (AST). The AST faithfully records the structure the programmer wrote down: variables, scopes, the nesting of expressions. But the moment we want to optimize, this structure sits too &amp;ldquo;high.&amp;rdquo; Consider the most unremarkable line, &lt;code&gt;x = x + 1&lt;/code&gt;: in the AST, the &lt;code&gt;x&lt;/code&gt; on the left and the &lt;code&gt;x&lt;/code&gt; on the right are the same name, and if the compiler wants to know &amp;ldquo;which assignment produced the value of the &lt;code&gt;x&lt;/code&gt; used here,&amp;rdquo; it has to repeatedly perform scope lookups and data-flow analysis. Names get shadowed, scopes nest, an assignment wipes out the old value, and all of this makes &amp;ldquo;where a value comes from and where it goes,&amp;rdquo; which ought to be the most basic thing, murky. What the optimizer wants most is exactly to lay the data flow out in the open.&lt;/p&gt;</description></item><item><title>15.3 The Optimizer</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/optimize/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/optimize/</guid><description>&lt;h1 id="153-the-optimizer"&gt;15.3 The Optimizer&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././ssa"&gt;15.2&lt;/a&gt; lowered the front end&amp;rsquo;s syntax tree down to the SSA intermediate
representation and explained why SSA&amp;rsquo;s &amp;ldquo;each variable is assigned exactly once&amp;rdquo;
makes the optimization passes both accurate and fast to write. This section
continues from there: on top of this representation, what optimizations does the
compiler actually run, and why precisely these few.&lt;/p&gt;
&lt;p&gt;To read the Go optimizer well, we first have to read its disposition. Faced with
the same task of turning a high-level language into machine code, GCC and LLVM
are willing to spend seconds or even tens of seconds kneading a function over and
over to win the last few percent of run-time performance. Go takes a different
road: it does only the batch of optimizations with the best cost-to-benefit
ratio, and hands the time it saves back to compilation speed
(&lt;a href="https://golang.design/under-the-hood/en/part1overview/ch01intro/history/"&gt;1.1&lt;/a&gt;). This is not a shortfall in
ability but a clear-eyed ordering of values, and this section will return to that
red line at the end. We first look at the optimizations Go is willing to do, then
at Profile-Guided Optimization (PGO), introduced in Go 1.21, which pushes
optimization from &amp;ldquo;static guessing&amp;rdquo; toward &amp;ldquo;data-driven.&amp;rdquo;&lt;/p&gt;</description></item><item><title>15.4 The Pointer Checker</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/unsafe/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/unsafe/</guid><description>&lt;h1 id="154-the-pointer-checker"&gt;15.4 The Pointer Checker&lt;/h1&gt;
&lt;p&gt;Go is a memory-safe language. In ordinary code, the type system guarantees that every pointer refers to a legal object of its declared type, garbage collection (&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/"&gt;13&lt;/a&gt;) guarantees that an object is not reclaimed while it is still referenced, and the runtime keeps out-of-bounds accesses behind bounds checks. These guarantees are not free. They rest on the premise that the compiler always knows the type and layout of every value. Yet there is always a small set of scenarios that need to step outside this system: interoperating with C (&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch15compile/cgo/"&gt;15.6&lt;/a&gt;) means interpreting a span of bytes according to C&amp;rsquo;s memory layout, laying out a system structure for the operating system means placing bytes one by one, and reinterpreting a &lt;code&gt;[]byte&lt;/code&gt; as a &lt;code&gt;string&lt;/code&gt; with zero copies (&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch05data/slice/"&gt;5.1&lt;/a&gt;) means letting two types share the same underlying memory. Go leaves an escape hatch for these scenarios: the &lt;code&gt;unsafe&lt;/code&gt; package.&lt;/p&gt;</description></item><item><title>15.5 Escape Analysis</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/escape/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/escape/</guid><description>&lt;h1 id="155-escape-analysis"&gt;15.5 Escape Analysis&lt;/h1&gt;
&lt;p&gt;Go programmers never manually decide whether a variable lives on the stack or the heap; the compiler&amp;rsquo;s &lt;strong&gt;escape analysis&lt;/strong&gt; does it automatically. It is the unsung hero of Go&amp;rsquo;s performance: keeping as many objects on the stack as possible greatly lightens the load on the garbage collector (&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/"&gt;13 Garbage Collection&lt;/a&gt;). This section explains how it decides, how it is implemented, and why it matters.&lt;/p&gt;
&lt;h2 id="1551-escape-deciding-stack-or-heap"&gt;15.5.1 Escape: Deciding Stack or Heap&lt;/h2&gt;
&lt;p&gt;The core question: should a variable be allocated on the &lt;strong&gt;stack&lt;/strong&gt; (vanishing automatically when the function returns, at zero GC cost) or on the &lt;strong&gt;heap&lt;/strong&gt; (with an indefinite lifetime, managed by the GC)? The criterion is &lt;strong&gt;lifetime&lt;/strong&gt;: if a reference to a variable may still be used after the function returns, it cannot live on the stack (the stack frame is destroyed on return) and must &lt;strong&gt;escape&lt;/strong&gt; to the heap. Escape analysis answers this question statically, deciding whether a variable&amp;rsquo;s address can leave the scope of the function it lives in.&lt;/p&gt;</description></item><item><title>15.6 cgo</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/cgo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/cgo/</guid><description>&lt;h1 id="156-cgo"&gt;15.6 cgo&lt;/h1&gt;
&lt;p&gt;&amp;ldquo;cgo is not Go.&amp;rdquo; This is the verdict Rob Pike handed down on cgo in a blog post. It names a thing that is easy to overlook: when you write &lt;code&gt;import &amp;quot;C&amp;quot;&lt;/code&gt; in a Go source file and then write a single line of &lt;code&gt;C.foo()&lt;/code&gt;, you have already stepped out of the world that the Go language drew for you and into another world, one made of C&amp;rsquo;s ABI, C&amp;rsquo;s stack, and C&amp;rsquo;s memory model. cgo is the bridge between these two worlds. The bridge is useful, but crossing it costs a toll, and the toll is not cheap.&lt;/p&gt;</description></item><item><title>15.7 Past, Present, and Future</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/future/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch15compile/future/</guid><description>&lt;h1 id="157-past-present-and-future"&gt;15.7 Past, Present, and Future&lt;/h1&gt;
&lt;p&gt;The compiler is the part of the Go toolchain that changes most often, yet remains the most transparent to users. Take the same source code, change nothing, recompile it with a new version, and it often comes out faster, smaller, and better, without you ever knowing what happened in between. This section pulls the camera back to look at the road the compiler itself has traveled, then at what it is doing now and where it is heading next. Running through all of it is one unchanging order of priorities: &lt;strong&gt;compilation speed comes first, quality of generated code second, and both are traded off under the constraint of being engineerable&lt;/strong&gt; (&lt;a href="https://golang.design/under-the-hood/en/part1overview/ch01intro/history/"&gt;1.1&lt;/a&gt;).&lt;/p&gt;</description></item><item><title>16.1 Runtime Deadlock Detection</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/deadlock/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/deadlock/</guid><description>&lt;h1 id="161-runtime-deadlock-detection"&gt;16.1 Runtime Deadlock Detection&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;fatal error: all goroutines are asleep - deadlock!&lt;/code&gt;, almost every Go programmer has seen this error. It
comes from the runtime&amp;rsquo;s built-in deadlock detector. This section first makes clear how it decides and when
it fires, then turns to something more important: what it can guarantee in theory, and what it is
&lt;strong&gt;structurally unable to detect&lt;/strong&gt;. The latter is the root of many production &amp;ldquo;hang&amp;rdquo; mysteries; understanding
it is worth more than memorizing that error message.&lt;/p&gt;</description></item><item><title>16.2 Race Detection</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/race/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/race/</guid><description>&lt;h1 id="162-race-detection"&gt;16.2 Race Detection&lt;/h1&gt;
&lt;p&gt;A data race is the most insidious and hardest-to-reproduce class of bug in concurrent programs. Its definition is short: if two goroutines
access the same memory address concurrently, at least one of them is a write, and no synchronization orders the two, then the program&amp;rsquo;s behavior
is undefined (&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/"&gt;11.9&lt;/a&gt;). &amp;ldquo;Undefined&amp;rdquo; is not as gentle as &amp;ldquo;you read a stale value&amp;rdquo;;
it means the compiler and the processor are both allowed to perform surprising reorderings, and the result may be right one time and wrong the next, may appear only under stress
load, only on a certain CPU, only in a certain version, just once in a while. There is no hope of catching this kind of bug by human code review. Go&amp;rsquo;s
&lt;strong&gt;race detector&lt;/strong&gt; (&lt;code&gt;-race&lt;/code&gt;) is exactly the tool that turns this from &amp;ldquo;reproduce it by luck&amp;rdquo; into &amp;ldquo;run it once and it tells you&amp;rdquo;. This section
explains its principle, the algorithmic cost behind it, and the two capability boundaries you must keep in mind.&lt;/p&gt;</description></item><item><title>16.3 Execution Tracing</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/trace/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/trace/</guid><description>&lt;h1 id="163-execution-tracing"&gt;16.3 Execution Tracing&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;pprof&lt;/code&gt; (&lt;a href=".././perf"&gt;16.5&lt;/a&gt;) answers the question &amp;ldquo;which functions is the time being spent in&amp;rdquo;. It aggregates CPU samples taken over a window into a call tree and tells you that &lt;code&gt;json.Marshal&lt;/code&gt; accounts for 30% of the CPU. But it cannot answer another class of question: a request took 50ms, and for 45ms of it the goroutine &lt;strong&gt;was not running at all&lt;/strong&gt;, it was waiting. Waiting for what? A lock? The network? Interrupted by GC? Or it wanted to run but had no P available (&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/steal/"&gt;9.2&lt;/a&gt;)? A CPU profile knows nothing about &amp;ldquo;waiting&amp;rdquo;, because it only samples the stack that is currently executing, and a blocked goroutine is on no CPU at all, so it is naturally never sampled.&lt;/p&gt;</description></item><item><title>16.4 Testing Code</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/testing/</guid><description>&lt;h1 id="164-testing-code"&gt;16.4 Testing Code&lt;/h1&gt;
&lt;p&gt;Testing in Go is not a bolt-on, it is a first-class citizen of the language toolchain. &lt;code&gt;go test&lt;/code&gt; is built in, the &lt;code&gt;testing&lt;/code&gt; package is standard, and convention replaces configuration. This set of design choices has deeply shaped Go&amp;rsquo;s engineering culture: in other languages, &amp;ldquo;whether to write tests at all, and which framework to use&amp;rdquo; is a decision that requires weighing trade-offs; in Go it is the default action. This section explains how this machinery runs, why it was designed this way, and how it grew from unit testing all the way to Go 1.18 fuzzing.&lt;/p&gt;</description></item><item><title>16.5 Benchmarking and Performance Profiling</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/perf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/perf/</guid><description>&lt;h1 id="165-benchmarking-and-performance-profiling"&gt;16.5 Benchmarking and Performance Profiling&lt;/h1&gt;
&lt;p&gt;The first principle of optimization is to measure before you act. Guessing at bottlenecks by intuition usually guesses wrong; the real hot spots are often not where you think they are. Go builds every tool this discipline requires straight into the toolchain: benchmarks answer &amp;ldquo;how fast,&amp;rdquo; profiling answers &amp;ldquo;where is it slow, where does the memory go,&amp;rdquo; and &lt;code&gt;benchstat&lt;/code&gt; uses statistics to answer &amp;ldquo;did this change actually make things faster, or is it just noise.&amp;rdquo; This section explains all three tools thoroughly and strings them into a measurement-driven loop of &amp;ldquo;profile to find the hot spot, change, benchmark to verify.&amp;rdquo; One level up, this loop joins with PGO (&lt;a href="../../ch15compile/optimize"&gt;15.3&lt;/a&gt;) and execution tracing (&lt;a href=".././trace"&gt;16.3&lt;/a&gt;) to form Go&amp;rsquo;s complete performance-engineering methodology.&lt;/p&gt;</description></item><item><title>16.6 Runtime Metrics</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/metric/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/metric/</guid><description>&lt;h1 id="166-runtime-metrics"&gt;16.6 Runtime Metrics&lt;/h1&gt;
&lt;p&gt;Profiling (&lt;a href=".././perf"&gt;16.5&lt;/a&gt;) and tracing (&lt;a href=".././trace"&gt;16.3&lt;/a&gt;) belong to the family of &amp;ldquo;pull it in to diagnose when something goes wrong&amp;rdquo; tools: they cost a fair amount, produce a lot of output, and suit the case where you already suspect a problem somewhere and want to capture a window of time or a single request to look at closely. But in production the more common question is not &amp;ldquo;profile this for me right now&amp;rdquo;; it is &amp;ldquo;has this service been healthy over the past week, when did it start degrading, and should we page someone at midnight?&amp;rdquo; Answering questions like these does not rely on a one-off deep dive. It relies on &lt;strong&gt;continuous, low-cost, long-retainable numbers&lt;/strong&gt;: how big the heap is, how often GC runs, whether the goroutine count is climbing, whether the tail of scheduling latency is rising. These numbers are &lt;strong&gt;runtime metrics&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>16.7 The Language Server Protocol</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/gopls/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/gopls/</guid><description>&lt;h1 id="167-the-language-server-protocol"&gt;16.7 The Language Server Protocol&lt;/h1&gt;
&lt;p&gt;Auto-completion, jump-to-definition, live error reporting, refactoring: in modern editors these features, on the Go side, are provided by &lt;strong&gt;&lt;code&gt;gopls&lt;/code&gt;&lt;/strong&gt; (the Go language server, pronounced &amp;ldquo;go please&amp;rdquo;). Behind it stands the &lt;strong&gt;Language Server Protocol&lt;/strong&gt; (LSP). This section makes three things clear: the combinatorial explosion that LSP untangles, how gopls builds on the reusable libraries of the compiler frontend, and why it deserves to be called the culmination of the Go toolchain&amp;rsquo;s design philosophy.&lt;/p&gt;</description></item><item><title>17.1 The Hard Parts of Dependency Management</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/challenges/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/challenges/</guid><description>&lt;h1 id="171-the-hard-parts-of-dependency-management"&gt;17.1 The Hard Parts of Dependency Management&lt;/h1&gt;
&lt;p&gt;Modern software is almost never written from scratch. For an ordinary server program, one level down the &lt;code&gt;import&lt;/code&gt; list you find a logging library, an HTTP router, a serializer; one level further down are the cryptography, compression, and network primitives that each of those depends on. The code that is actually yours may be less than one percent of the whole dependency graph. This brings the dividend of reuse, and it also brings a question that is not yours by rights yet must be answered by you: &lt;strong&gt;for every package in this graph, which version should you use?&lt;/strong&gt; This section is in no hurry to give Go&amp;rsquo;s answer; first we want to make the difficulty of the problem itself clear. There are two main threads to it: one is &lt;strong&gt;how to choose a version&lt;/strong&gt; (diamond dependencies and constraint solving), the other is &lt;strong&gt;how to keep it from drifting once chosen&lt;/strong&gt; (reproducible builds). Only once these two are understood can you see why the &amp;ldquo;minimum version selection&amp;rdquo; scheme of &lt;a href=".././minimum"&gt;17.3&lt;/a&gt; deserves its own design, and what price Go paid to get there.&lt;/p&gt;</description></item><item><title>17.2 Semantic Version Management</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/semantics/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/semantics/</guid><description>&lt;h1 id="172-semantic-version-management"&gt;17.2 Semantic Version Management&lt;/h1&gt;
&lt;p&gt;To manage versions, we first have to make version numbers &lt;strong&gt;mean something&lt;/strong&gt;. &lt;a href=".././challenges"&gt;17.1&lt;/a&gt;
reduced the difficulty of dependency management to two points: version conflicts in diamond
dependencies, and reproducible builds across machines and across time. Whether these two can be
solved depends on a more basic premise, &lt;strong&gt;what a version number actually promises&lt;/strong&gt;. If the
relationship between &lt;code&gt;v1.5&lt;/code&gt; and &lt;code&gt;v1.4&lt;/code&gt; were entirely unpredictable, then no selection algorithm could
get started, and we would be forced back to a solver that &amp;ldquo;tries every pair of versions&amp;rdquo;. The approach
Go modules take is to first turn the version number into a &lt;strong&gt;contract a machine can trust&lt;/strong&gt;, and then,
on top of that contract, propose one distinctive and uncompromising rule, &lt;strong&gt;semantic import
versioning&lt;/strong&gt;. This section makes both of these clear. They are the premise on which the version
selection algorithm of &lt;a href=".././minimum"&gt;17.3&lt;/a&gt; can stand, and stand simply enough to be &amp;ldquo;a single graph
traversal&amp;rdquo;.&lt;/p&gt;</description></item><item><title>17.3 Minimal Version Selection</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/minimum/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/minimum/</guid><description>&lt;h1 id="173-minimal-version-selection"&gt;17.3 Minimal Version Selection&lt;/h1&gt;
&lt;p&gt;Having settled on semantic versioning (&lt;a href=".././semantics"&gt;17.2&lt;/a&gt;), one last question remains: when different modules in the dependency graph require different versions of the same dependency, &lt;strong&gt;which version do we pick&lt;/strong&gt;? Go&amp;rsquo;s answer is a counterintuitive yet remarkably concise algorithm, &lt;strong&gt;Minimal Version Selection&lt;/strong&gt; (MVS). It is the most distinctive and the most thought-provoking part of Go&amp;rsquo;s module design: other package managers turned this into a problem that needs a constraint solver, while Go compressed it into a single pass over a graph. This section first lays out the rules, then looks at why it can be this simple, and finally places it back within the broader lineage of the field to see exactly what it trades away and what it gains.&lt;/p&gt;</description></item><item><title>17.4 The vgo versus dep Dispute</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/fight/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch17modules/fight/</guid><description>&lt;h1 id="174-the-vgo-versus-dep-dispute"&gt;17.4 The vgo versus dep Dispute&lt;/h1&gt;
&lt;p&gt;Today&amp;rsquo;s Go Modules did not exist from the start. They were born out of a rather dramatic, and rather controversial, community episode: &lt;strong&gt;the vgo versus dep dispute&lt;/strong&gt;. This history is not mere gossip. It reflects the real tension among open-source project governance, technical decision-making, and community sentiment. It is the final piece for understanding why Go Modules are the way they are today, and it is also a concentrated performance, at the toolchain level, of the design philosophy this book has been discussing all along.&lt;/p&gt;</description></item><item><title>Closing Words: Where Is Go Headed?</title><link>https://golang.design/under-the-hood/en/finalwords/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/finalwords/</guid><description>&lt;h1 id="closing-words-where-is-go-headed"&gt;Closing Words: Where Is Go Headed?&lt;/h1&gt;
&lt;p&gt;Having read this far, the reader has walked with the book through Go&amp;rsquo;s five major parts: its panorama and history, its language features, concurrency, memory, and the compiler and toolchain. As a conclusion, let us step back from the specific implementation details and talk about the legacy Go leaves behind, the challenges it currently faces, and where it might be headed.&lt;/p&gt;
&lt;h2 id="what-go-leaves-behind"&gt;What Go Leaves Behind&lt;/h2&gt;
&lt;p&gt;Looking back over the whole book, Go&amp;rsquo;s deepest legacy is perhaps not any single concrete technique, but a &lt;strong&gt;design stance&lt;/strong&gt; it demonstrates again and again: place complexity where it disturbs the user least, and let simplicity be the result rather than the starting point. This thread shows itself everywhere in the book. The scheduler (&lt;a href=".././part3concurrency/ch09sched/readme"&gt;9&lt;/a&gt;) hides the complexity of thread management inside the runtime and gives the user only a single &lt;code&gt;go&lt;/code&gt; keyword; garbage collection (&lt;a href=".././part4memory/ch13gc/readme"&gt;13&lt;/a&gt;) keeps all the subtlety of sub-millisecond pauses internal, so the user needs almost no tuning; generics (&lt;a href=".././part2lang/ch08generics/readme"&gt;8&lt;/a&gt;) waited thirteen years just to find an implementation that sacrifices neither compilation speed nor simplicity; the module system (&lt;a href=".././part5toolchain/ch17modules/readme"&gt;17&lt;/a&gt;) replaced the industry&amp;rsquo;s usual constraint solver with minimal version selection, the simplest possible algorithm. Each of these answers the same question: by what right does a given piece of complexity deserve to be introduced?&lt;/p&gt;</description></item><item><title>Appendix A: Glossary</title><link>https://golang.design/under-the-hood/en/glossary/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/glossary/</guid><description>&lt;h1 id="glossary"&gt;Glossary&lt;/h1&gt;
&lt;p&gt;This appendix collects the main terms that appear in the book, grouped by topic and ordered alphabetically by their English names. For each term it gives the chapter where the term is mainly developed, so the reader can look it back up easily.&lt;/p&gt;
&lt;h2 id="concurrency-and-scheduling"&gt;Concurrency and Scheduling&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Chapter&lt;/th&gt;
 &lt;th&gt;English&lt;/th&gt;
 &lt;th&gt;Abbreviation&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Back Edge&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/preemption/"&gt;9.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Back Edge&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cooperative Preemption&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/preemption/"&gt;9.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Cooperative Preemption&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Communicating Sequential Processes&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part1overview/ch01intro/csp/"&gt;1.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Communicating Sequential Processes&lt;/td&gt;
 &lt;td&gt;CSP&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Goroutine&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/mpg/"&gt;9.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Goroutine&lt;/td&gt;
 &lt;td&gt;G/g&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Machine (Thread)&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/mpg/"&gt;9.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Machine&lt;/td&gt;
 &lt;td&gt;M/m&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Network Poller&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/poller/"&gt;9.9&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Network Poller&lt;/td&gt;
 &lt;td&gt;netpoll&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Non-spinning&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/schedule/"&gt;9.4&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Non-spinning&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Preemptive&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/preemption/"&gt;9.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Preemptive&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Processor&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/mpg/"&gt;9.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Processor&lt;/td&gt;
 &lt;td&gt;P/p&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Safepoint&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/preemption/"&gt;9.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Safepoint&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Scheduler&lt;/td&gt;
 &lt;td&gt;&lt;a href=".././part3concurrency/ch09sched/readme"&gt;9&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Scheduler&lt;/td&gt;
 &lt;td&gt;sched&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Spinning&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/schedule/"&gt;9.4&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Spinning&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;System Monitor&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/sysmon/"&gt;9.8&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;System Monitor&lt;/td&gt;
 &lt;td&gt;sysmon&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Work Stealing&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/steal/"&gt;9.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Work Stealing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="synchronization-and-the-memory-model"&gt;Synchronization and the Memory Model&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Chapter&lt;/th&gt;
 &lt;th&gt;English&lt;/th&gt;
 &lt;th&gt;Abbreviation&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Atomic Operation&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/"&gt;11.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Atomic Operation&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Compare-And-Swap&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/"&gt;11.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Compare-And-Swap&lt;/td&gt;
 &lt;td&gt;CAS&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Condition Variable&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/cond/"&gt;11.4&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Condition Variable&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Data Race&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/"&gt;11.9&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Data Race&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Happens-Before&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/"&gt;11.9&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Happens-Before&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Lock-free&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/"&gt;11.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Lock-free&lt;/td&gt;
 &lt;td&gt;LF&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Memory Barrier&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/"&gt;11.9&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Memory Barrier&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Sequential Consistency&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/"&gt;11.9&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Sequential Consistency&lt;/td&gt;
 &lt;td&gt;SC&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;False Sharing&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/component/"&gt;12.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;False Sharing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;True Sharing&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/component/"&gt;12.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;True Sharing&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Wait-free&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/"&gt;11.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Wait-free&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="memory-allocation"&gt;Memory Allocation&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Chapter&lt;/th&gt;
 &lt;th&gt;English&lt;/th&gt;
 &lt;th&gt;Abbreviation&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Arena&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/init/"&gt;12.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Arena&lt;/td&gt;
 &lt;td&gt;heapArena&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Arena Hint&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/init/"&gt;12.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Arena Hint&lt;/td&gt;
 &lt;td&gt;arenaHint&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Fast Path&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/basic/"&gt;12.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Fast Path&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Free List&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/component/"&gt;12.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Free List&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Heap&lt;/td&gt;
 &lt;td&gt;&lt;a href=".././part4memory/ch12alloc/readme"&gt;12&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Heap&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Large Object&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/largealloc/"&gt;12.4&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Large Object&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Page&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/pagealloc/"&gt;12.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Page&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Page Allocator&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/pagealloc/"&gt;12.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Page Allocator&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Size Class&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/basic/"&gt;12.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Size Class&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Small Object&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/smallalloc/"&gt;12.5&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Small Object&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Slow Path&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/basic/"&gt;12.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Slow Path&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Tiny Allocator&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/tinyalloc/"&gt;12.6&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Tiny Allocator&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Tiny Object&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch12alloc/tinyalloc/"&gt;12.6&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Tiny Object&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="garbage-collection"&gt;Garbage Collection&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Chapter&lt;/th&gt;
 &lt;th&gt;English&lt;/th&gt;
 &lt;th&gt;Abbreviation&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Bitmap&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/sweep/"&gt;13.5&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Bitmap&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Collector&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/"&gt;13.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Collector&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Conservative&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/safe/"&gt;13.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Conservative&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Finalizer&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/finalizer/"&gt;13.10&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Finalizer&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Garbage Collection&lt;/td&gt;
 &lt;td&gt;&lt;a href=".././part4memory/ch13gc/readme"&gt;13&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Garbage Collection&lt;/td&gt;
 &lt;td&gt;GC&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Generational Hypothesis&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/generational/"&gt;13.8&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Generational Hypothesis&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Hybrid Write Barrier&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/barrier/"&gt;13.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Hybrid Write Barrier&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Liveness&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/"&gt;13.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Liveness&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Mark Assist&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/mark/"&gt;13.4&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Mark Assist&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Mark-Sweep&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/"&gt;13.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Mark-Sweep&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Mutator&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/"&gt;13.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Mutator&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Pacer&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/pacing/"&gt;13.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Pacer&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Reachability&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/"&gt;13.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Reachability&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Remembered Set&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/generational/"&gt;13.8&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Remembered Set&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Stop the World&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/pacing/"&gt;13.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Stop the World&lt;/td&gt;
 &lt;td&gt;STW&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Tricolour Abstraction&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/basic/"&gt;13.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Tricolour Abstraction&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Write Barrier&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/barrier/"&gt;13.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Write Barrier&lt;/td&gt;
 &lt;td&gt;WB/wb&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="execution-stack"&gt;Execution Stack&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Chapter&lt;/th&gt;
 &lt;th&gt;English&lt;/th&gt;
 &lt;th&gt;Abbreviation&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Contiguous Stack&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch14stack/design/"&gt;14.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Contiguous Stack&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Prologue&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part1overview/ch02asm/callconv/"&gt;2.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Prologue&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Epilogue&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch14stack/grow/"&gt;14.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Epilogue&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Stack&lt;/td&gt;
 &lt;td&gt;&lt;a href=".././part4memory/ch14stack/readme"&gt;14&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Stack&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Stack Copy&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch14stack/copy/"&gt;14.4&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Stack Copy&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Stack Growth&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch14stack/grow/"&gt;14.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Stack Growth&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="language-features-and-the-compiler"&gt;Language Features and the Compiler&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Chapter&lt;/th&gt;
 &lt;th&gt;English&lt;/th&gt;
 &lt;th&gt;Abbreviation&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Calling Convention&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part1overview/ch02asm/callconv/"&gt;2.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Calling Convention / ABI&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Defer Bit&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch06func/defer/"&gt;6.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Defer Bit&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Devirtualization&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch15compile/optimize/"&gt;15.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Devirtualization&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Escape Analysis&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch15compile/escape/"&gt;15.5&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Escape Analysis&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;GC Shape&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch08generics/history/"&gt;8.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;GC Shape&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Inlining&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch15compile/optimize/"&gt;15.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Inlining&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Interface Table&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch04type/interface/"&gt;4.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Interface Table&lt;/td&gt;
 &lt;td&gt;itab&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Open-coded Defer&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch06func/defer/"&gt;6.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Open-coded Defer&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Profile-Guided Optimization&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch15compile/optimize/"&gt;15.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Profile-Guided Optimization&lt;/td&gt;
 &lt;td&gt;PGO&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Static Single Assignment&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch15compile/ssa/"&gt;15.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Static Single Assignment&lt;/td&gt;
 &lt;td&gt;SSA&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Type Set&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch08generics/checker/"&gt;8.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Type Set&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Type Descriptor&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch04type/type/"&gt;4.1&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Type Descriptor&lt;/td&gt;
 &lt;td&gt;_type&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="modules-and-the-toolchain"&gt;Modules and the Toolchain&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Term&lt;/th&gt;
 &lt;th&gt;Chapter&lt;/th&gt;
 &lt;th&gt;English&lt;/th&gt;
 &lt;th&gt;Abbreviation&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Language Server Protocol&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch16tools/gopls/"&gt;16.7&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Language Server Protocol&lt;/td&gt;
 &lt;td&gt;LSP&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Minimal Version Selection&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch17modules/minimum/"&gt;17.3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Minimal Version Selection&lt;/td&gt;
 &lt;td&gt;MVS&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Race Detector&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch16tools/race/"&gt;16.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Race Detector&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Semantic Import Versioning&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch17modules/semantics/"&gt;17.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Semantic Import Versioning&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Semantic Versioning&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://golang.design/under-the-hood/en/part5toolchain/ch17modules/semantics/"&gt;17.2&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Semantic Versioning&lt;/td&gt;
 &lt;td&gt;semver&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>Support the Author</title><link>https://golang.design/under-the-hood/en/donate/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/donate/</guid><description>&lt;h1 id="support-the-author"&gt;Support the Author&lt;/h1&gt;
&lt;p&gt;Thank you for reading this far. This book has been free and open from beginning to end, and from the very first line until now, the entire cost of writing, proofreading, and updating it has been borne by the author alone. If these words once helped you make sense of an obscure piece of source code late at night, or saved you some time fumbling through a problem at work, the author would be glad to hear it.&lt;/p&gt;</description></item></channel></rss>