<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Chapter 14 Execution Stack Management on Go: Under the Hood</title><link>https://golang.design/under-the-hood/en/part4memory/ch14stack/</link><description>Recent content in Chapter 14 Execution Stack Management on Go: Under the Hood</description><generator>Hugo</generator><language>en</language><atom:link href="https://golang.design/under-the-hood/en/part4memory/ch14stack/index.xml" rel="self" type="application/rss+xml"/><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></channel></rss>