<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>GC on 我的技术博客</title><link>https://buvidk1234.github.io/tags/gc/</link><description>Recent content in GC on 我的技术博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 18 Aug 2026 00:14:00 +0800</lastBuildDate><atom:link href="https://buvidk1234.github.io/tags/gc/index.xml" rel="self" type="application/rss+xml"/><item><title>Go Runtime（五）：GC、写屏障与Pacer</title><link>https://buvidk1234.github.io/posts/go-runtime-05-gc/</link><pubDate>Tue, 18 Aug 2026 00:14:00 +0800</pubDate><guid>https://buvidk1234.github.io/posts/go-runtime-05-gc/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源码基线为 &lt;strong&gt;Go 1.26.2、Linux/amd64，默认 GOEXPERIMENT&lt;/strong&gt;。Go 1.26.2 源码包含 build-tag 隔离的 Green Tea GC 实现，但默认 &lt;code&gt;GOEXPERIMENT&lt;/code&gt; 下 &lt;code&gt;goexperiment.GreenTeaGC == false&lt;/code&gt;；本文主线分析默认标记器，不把实验实现混入结论。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Go GC 的核心不是“三色”这个名词，而是在用户 goroutine 持续修改对象图时，怎样并发找出仍然可达的对象，并把暂停时间与 CPU、内存开销控制在目标范围内。&lt;/p&gt;
&lt;p&gt;一轮 GC 可以理解为四套机制协作：标记算法判断对象生死，写屏障维护并发正确性，分配 goroutine 通过 assist 偿还标记债务，pacer 控制何时开始以及投入多少资源。&lt;/p&gt;
&lt;h2 id="为什么需要gc"&gt;为什么需要GC&lt;/h2&gt;
&lt;p&gt;函数返回只能自然回收栈帧，无法决定堆对象是否仍被其他对象引用：&lt;/p&gt;
&lt;details class="code-fold" open&gt;
&lt;summary&gt;GO&lt;/summary&gt;&lt;div class="highlight"&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;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&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 class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&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="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="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;newNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&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 class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Node&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="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;p&gt;对象可能通过全局变量、其他堆对象、goroutine 栈或 runtime 结构继续可达。GC 必须从一组根出发遍历引用图，未被发现的堆对象才可以回收。&lt;/p&gt;
&lt;h2 id="根对象"&gt;根对象&lt;/h2&gt;
&lt;p&gt;典型根包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;全局变量和包级数据中的指针。&lt;/li&gt;
&lt;li&gt;各 goroutine 活动栈帧中的指针。&lt;/li&gt;
&lt;li&gt;寄存器或保存执行现场中的指针。&lt;/li&gt;
&lt;li&gt;runtime 持有的特定对象引用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;编译器生成的类型位图和栈图告诉 GC 哪些位置是指针。Go 的标记器不会把任意看起来像地址的整数都当作指针，这提高了准确性，也要求 syscall、汇编和 cgo 遵守指针与栈管理规则。&lt;/p&gt;</description></item></channel></rss>