<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>第 3 章 程序的生命周期 on Go 语言原本</title>
    <link>/zh-cn/part1overview/ch03life/</link>
    <description>Recent content in 第 3 章 程序的生命周期 on Go 语言原本</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <atom:link href="/zh-cn/part1overview/ch03life/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>3.1 从 `go` 命令谈起</title>
      <link>/zh-cn/part1overview/ch03life/cmd/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part1overview/ch03life/cmd/</guid>
      <description>&lt;h1 id=&#34;31-从-go-命令谈起&#34;&gt;3.1 从 &lt;code&gt;go&lt;/code&gt; 命令谈起&lt;/h1&gt;&#xA;&lt;p&gt;Go 程序的生命周期要从执行 &lt;code&gt;go&lt;/code&gt; 命令开始谈起。读者每天敲下的 &lt;code&gt;go build&lt;/code&gt;、&lt;code&gt;go test&lt;/code&gt;、&lt;code&gt;go run&lt;/code&gt;，&#xA;看上去只是「把源码变成二进制」，背后却藏着一个常被误解的事实：&lt;code&gt;go&lt;/code&gt; 本身并不是编译器。它是一个&#xA;&lt;strong&gt;构建编排器&lt;/strong&gt;（build orchestrator），负责把一次构建分解成许多道工序，安排它们的先后与并行，&#xA;再逐道调用真正的工具，编译器 &lt;code&gt;compile&lt;/code&gt;（&lt;a href=&#34;.././compile&#34;&gt;3.2&lt;/a&gt;）、汇编器 &lt;code&gt;asm&lt;/code&gt;、链接器 &lt;code&gt;link&lt;/code&gt;&#xA;（&lt;a href=&#34;.././link&#34;&gt;3.4&lt;/a&gt;）。本节先把这层编排关系讲清楚，它是后续几节的总纲：读懂了 &lt;code&gt;go&lt;/code&gt; 如何把一次&#xA;构建拆成一张图、如何用内容寻址的缓存避免重复劳动，再去看编译与链接的细节，就有了落脚的框架。&lt;/p&gt;&#xA;&lt;h2 id=&#34;311-go-是构建编排器不是编译器&#34;&gt;3.1.1 &lt;code&gt;go&lt;/code&gt; 是构建编排器，不是编译器&lt;/h2&gt;&#xA;&lt;p&gt;把一个最小程序的构建过程摊开，最直接的办法是 &lt;code&gt;go build -x&lt;/code&gt;，它会打印出 &lt;code&gt;go&lt;/code&gt; 实际执行的每一条&#xA;子命令。对一个只有一行 &lt;code&gt;fmt.Println&lt;/code&gt; 的 &lt;code&gt;main&lt;/code&gt; 包，输出的骨架是这样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ go build -x -o /dev/null .&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;WORK&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/tmp/go-build1449454186&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p &lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat &amp;gt;&lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/importcfg &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt; &amp;#39;EOF&amp;#39; # internal&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;# import config&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;packagefile fmt=/Users/.../go-build/7d/7d74...-d&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;packagefile runtime=/Users/.../go-build/60/60cb...-d&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 调用编译器，把 main.go 编成归档 _pkg_.a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.../pkg/tool/darwin_arm64/compile -o &lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/_pkg_.a -p main -lang&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;go1.26 &lt;span class=&#34;se&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    -complete -buildid ... -importcfg &lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/importcfg -pack ./main.go&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.../pkg/tool/darwin_arm64/buildid -w &lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/_pkg_.a &lt;span class=&#34;c1&#34;&gt;# internal&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cp &lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/_pkg_.a /Users/.../go-build/82/8256...-d &lt;span class=&#34;c1&#34;&gt;# internal&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 写出链接配置，再调用链接器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat &amp;gt;&lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/importcfg.link &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt; &amp;#39;EOF&amp;#39; # internal&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;packagefile demo=$WORK/b001/_pkg_.a&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;packagefile fmt=/Users/.../go-build/7d/7d74...-d&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EOF&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;.../pkg/tool/darwin_arm64/link -o &lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/exe/a.out -importcfg ... &lt;span class=&#34;nv&#34;&gt;$WORK&lt;/span&gt;/b001/_pkg_.a&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;go&lt;/code&gt; 自己做的事，是建一个临时工作目录、写出一份份 &lt;code&gt;importcfg&lt;/code&gt;（告诉编译器与链接器每个依赖包的&#xA;归档在磁盘何处），然后 &lt;code&gt;exec&lt;/code&gt; 出 &lt;code&gt;compile&lt;/code&gt; 与 &lt;code&gt;link&lt;/code&gt; 这两个独立的可执行文件。源文件到目标代码&#xA;的真正翻译，发生在 &lt;code&gt;go&lt;/code&gt; 之外的工具里。这种「主程序只负责编排、把脏活交给独立工具」的结构，在&#xA;&lt;code&gt;go&lt;/code&gt; 命令的内部用两个数据类型承载：&lt;code&gt;Builder&lt;/code&gt; 持有整次构建的共享状态（工作目录、各类缓存、并行度&#xA;控制），&lt;code&gt;Action&lt;/code&gt; 则是构建图上的一个节点，描述「一道要做的工序」：&lt;/p&gt;</description>
    </item>
    <item>
      <title>3.2 Go 程序编译流程</title>
      <link>/zh-cn/part1overview/ch03life/compile/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part1overview/ch03life/compile/</guid>
      <description>&lt;h1 id=&#34;32-go-程序编译流程&#34;&gt;3.2 Go 程序编译流程&lt;/h1&gt;&#xA;&lt;p&gt;&lt;a href=&#34;.././cmd&#34;&gt;3.1&lt;/a&gt; 说 &lt;code&gt;go build&lt;/code&gt; 背后真正干活的是 &lt;code&gt;compile&lt;/code&gt; 与 &lt;code&gt;link&lt;/code&gt; 两支程序。这一节把镜头推近到&#xA;&lt;code&gt;compile&lt;/code&gt;，给出它从一份 &lt;code&gt;.go&lt;/code&gt; 源文件到一个 &lt;code&gt;.o&lt;/code&gt; 目标文件之间走过的全程：每个阶段拿到什么、&#xA;吐出什么、为什么这样切分。本节是编译流水线的&lt;strong&gt;全景图&lt;/strong&gt;，每个阶段的内部机理（文法如何设计、&#xA;类型检查用什么算法、SSA 的优化规则）留给 &lt;a href=&#34;../../../part5toolchain/ch15compile/readme&#34;&gt;第 15 章&lt;/a&gt;&#xA;逐一展开，这里只负责把它们串成一条线，并指出两条贯穿始终的暗线。&lt;/p&gt;&#xA;&lt;p&gt;为避免落回逐字翻译编译器目录结构的窠臼，下文用&lt;strong&gt;一个贯穿全程的小例子&lt;/strong&gt;来串起所有阶段。&#xA;请记住这段函数，它会被流水线反复揉捏，直到变成机器码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;send&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;go&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;work&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 启动一个新 goroutine&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ch&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 向 channel 发送&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;它只有两行，却恰好藏着本节要强调的第二条暗线：&lt;code&gt;go&lt;/code&gt; 与 &lt;code&gt;&amp;lt;-&lt;/code&gt; 这样的语言关键字，最终都不是&#xA;靠 CPU 指令直接实现的，而是被编译器&lt;strong&gt;翻译成对运行时的函数调用&lt;/strong&gt;。先把流水线看完，再回头&#xA;解剖这两行。&lt;/p&gt;&#xA;&lt;h2 id=&#34;321-两条暗线为何要先讲它们&#34;&gt;3.2.1 两条暗线：为何要先讲它们&lt;/h2&gt;&#xA;&lt;p&gt;把流水线的细节铺开之前，先点明两个贯穿全程的设计取向，后面每个阶段都在为它们服务。&lt;/p&gt;&#xA;&lt;p&gt;第一条暗线是&lt;strong&gt;编译速度本身是一等约束&lt;/strong&gt;。Go 从设计之初就把「编译要快」当作语言目标而非事后&#xA;优化（&lt;a href=&#34;../../ch01intro/history&#34;&gt;1.1&lt;/a&gt;）。这个目标渗进了语法、依赖管理与编译器结构的每一层：&#xA;文法被设计成可以不回溯地快速解析，依赖以编译期产出的&lt;strong&gt;紧凑导出数据&lt;/strong&gt;而非源码传递，且不存在&#xA;C/C++ 那种会层层传染的 &lt;code&gt;#include&lt;/code&gt;。Rob Pike 在《Go at Google》里把这一点列为 Go 诞生的直接&#xA;动机，当年 Google 一次大型 C++ 构建动辄以小时计，而 Go 要做到「按一下回车就编译完」。&lt;/p&gt;</description>
    </item>
    <item>
      <title>3.3 语言的自举</title>
      <link>/zh-cn/part1overview/ch03life/bootstrap/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part1overview/ch03life/bootstrap/</guid>
      <description>&lt;h1 id=&#34;33-语言的自举&#34;&gt;3.3 语言的自举&lt;/h1&gt;&#xA;&lt;p&gt;一个问题听起来像悖论：Go 的编译器、汇编器、链接器与运行时如今都用 Go 写成，那么第一个能编译&#xA;Go 的程序是从哪里来的？没有 Go 编译器，怎么编译出 Go 编译器？这就是&lt;strong&gt;自举&lt;/strong&gt;（bootstrapping）。&#xA;它既是「先有鸡还是先有蛋」的经典困局，也是 Go 工具链演化史上一段可被精确复述的工程。本节&#xA;回答三件事：这只蛋最初是怎么孵出来的；自举之后，构建一个新版 Go 的链条如何运转，以及它对&#xA;引导版本的要求为何逐年抬升；最后，为什么一门语言「用自己实现自己」值得郑重对待。&lt;/p&gt;&#xA;&lt;h2 id=&#34;331-先有蛋从-c-写的工具链到-go-写的工具链&#34;&gt;3.3.1 先有蛋：从 C 写的工具链到 Go 写的工具链&lt;/h2&gt;&#xA;&lt;p&gt;自举的前提，是先有一个不依赖自身的起点。Go 工具链最初（到 &lt;strong&gt;Go 1.4&lt;/strong&gt;，2014 年）的编译器、&#xA;汇编器、链接器与 &lt;code&gt;cmd/dist&lt;/code&gt; 都是用 &lt;strong&gt;C&lt;/strong&gt; 写的，编译器沿用了 Plan 9 的命名（&lt;code&gt;5c&lt;/code&gt;、&lt;code&gt;6c&lt;/code&gt;、&lt;code&gt;8c&lt;/code&gt;、&#xA;&lt;code&gt;9c&lt;/code&gt; 等，数字对应不同的目标架构）。这套 C 程序由系统自带的 &lt;code&gt;gcc&lt;/code&gt; 或 &lt;code&gt;clang&lt;/code&gt; 编译，于是构建&#xA;Go 不需要任何已存在的 Go,这便是那只「蛋」。&lt;/p&gt;&#xA;&lt;p&gt;从 &lt;strong&gt;Go 1.5（2015 年 8 月）&lt;strong&gt;起，Go 完成了一次里程碑式的转变：编译器与运行时被&lt;/strong&gt;整体用 Go&#xA;重写&lt;/strong&gt;，C 工具链被删除，工具链从此可以自我引导。这步棋的代价与收益都很实在。收益是，编译器&#xA;开发者从此用 Go 这门内存安全、并发友好、自带测试与剖析工具的语言来维护工具链，编译器里的&#xA;bug 可以用 Go 自己的调试手段去查；运行时与编译器共用一套语言，跨边界的协作（如逃逸分析与&#xA;栈管理）也更顺。代价是，构建 Go 不再像编译一段 C 那样自给自足，它现在需要「另一个已经能用的&#xA;Go」。如何用一个旧的 Go 造出一个新的 Go，就成了此后每个版本都要回答的问题。&lt;/p&gt;</description>
    </item>
    <item>
      <title>3.4 模块链接</title>
      <link>/zh-cn/part1overview/ch03life/link/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part1overview/ch03life/link/</guid>
      <description>&lt;h1 id=&#34;34-模块链接&#34;&gt;3.4 模块链接&lt;/h1&gt;&#xA;&lt;p&gt;编译器（&lt;a href=&#34;.././compile&#34;&gt;3.2&lt;/a&gt;）把每个包变成一个目标文件，但目标文件还不能直接运行。它们彼此&#xA;引用着对方的函数与变量，地址尚未确定，还缺运行时的支撑。把这些碎片拼成一个完整、可加载执行&#xA;的程序，是&lt;strong&gt;链接器&lt;/strong&gt;（&lt;code&gt;cmd/link&lt;/code&gt;，通常以 &lt;code&gt;go tool link&lt;/code&gt; 的形式被 &lt;code&gt;go build&lt;/code&gt; 调起）的活。这一节&#xA;看链接器做了哪几件事，以及 Go 在链接上的几处独特选择,它们一同解释了为什么一个 Go 程序往往是&#xA;一个「拷过去就能跑」的自包含文件。&lt;/p&gt;&#xA;&lt;h2 id=&#34;341-链接器做的事&#34;&gt;3.4.1 链接器做的事&lt;/h2&gt;&#xA;&lt;p&gt;链接器的输入是一个 main 包的目标文件，加上它递归依赖的所有包（含整个运行时）的目标文件；&#xA;输出是一个可被操作系统加载执行的二进制。中间它要顺序完成几件关键工作：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;符号解析&lt;/strong&gt;（symbol resolution）：把每一处对外部符号的&lt;strong&gt;引用&lt;/strong&gt;，绑定到它在某个目标文件里的&#xA;唯一&lt;strong&gt;定义&lt;/strong&gt;。一个符号就是一个有名字的地址,某个函数的入口、某个全局变量的存储。A 包里写&#xA;&lt;code&gt;fmt.Println(...)&lt;/code&gt;，编译 A 时并不知道 &lt;code&gt;fmt.Println&lt;/code&gt; 在哪，只留下一个待解析的引用；链接器把它&#xA;接到 &lt;code&gt;fmt&lt;/code&gt; 包目标文件里那份定义上。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;布局&lt;/strong&gt;（layout）：把所有符号的机器码与数据，按种类安排进可执行文件的各个段,代码进 text、&#xA;可读写数据进 data、只读数据（字符串字面量、类型信息）进 rodata 等。布局一旦定下，每个符号的&#xA;最终地址也就确定了。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;重定位&lt;/strong&gt;（relocation）：地址定下后，回头修正所有引用处填的临时地址。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;死代码消除&lt;/strong&gt;（dead-code elimination）：从入口出发不可达的函数与变量，根本不写进最终二进制。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;最后产出的，是一个静态布局完毕、地址全部填实的文件。下面三节分别细看其中最值得说的三处：&#xA;重定位（3.4.2）、死代码消除（3.4.3）、以及「运行时也被一并链接进来」这一 Go 的标志性后果&#xA;（3.4.4）。&lt;/p&gt;&#xA;&#xA;&lt;script src=&#34;/mermaid.min.js&#34;&gt;&lt;/script&gt;&#xA;&lt;script src=&#34;/mermaid-init.js&#34;&gt;&lt;/script&gt;&#xA;&#xA;&#xA;&lt;pre class=&#34;mermaid&#34;&gt;flowchart LR&#xA;    OBJ[&amp;#34;main.a &amp;#43; 依赖包目标文件&amp;lt;br/&amp;gt;(含整个 runtime)&amp;#34;] --&amp;gt; LOAD[&amp;#34;装载符号&amp;lt;br/&amp;gt;loader 读入&amp;#34;]&#xA;    LOAD --&amp;gt; RESOLVE[&amp;#34;符号解析&amp;lt;br/&amp;gt;引用 → 定义&amp;#34;]&#xA;    RESOLVE --&amp;gt; DEAD[&amp;#34;死代码消除&amp;lt;br/&amp;gt;从 main.main 标记可达&amp;#34;]&#xA;    DEAD --&amp;gt; LAYOUT[&amp;#34;段布局&amp;lt;br/&amp;gt;text/data/rodata&amp;#34;]&#xA;    LAYOUT --&amp;gt; RELOC[&amp;#34;重定位&amp;lt;br/&amp;gt;填实地址&amp;#34;]&#xA;    RELOC --&amp;gt; BIN[&amp;#34;可执行二进制&amp;#34;]&lt;/pre&gt;&#xA;&lt;h2 id=&#34;342-符号解析与重定位&#34;&gt;3.4.2 符号解析与重定位&lt;/h2&gt;&#xA;&lt;p&gt;这两步是链接的核心机制，值得稍微形式化一点。&lt;/p&gt;</description>
    </item>
    <item>
      <title>3.5 Go 程序启动引导</title>
      <link>/zh-cn/part1overview/ch03life/boot/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part1overview/ch03life/boot/</guid>
      <description>&lt;h1 id=&#34;35-go-程序启动引导&#34;&gt;3.5 Go 程序启动引导&lt;/h1&gt;&#xA;&lt;p&gt;读者写下的 &lt;code&gt;main&lt;/code&gt; 函数，并不是程序真正的第一条指令。当操作系统把控制权交给一个 Go&#xA;可执行文件时，跑起来的是运行时（runtime）：它要在主线程上铺好执行栈、绑定线程本地存储、&#xA;量出 CPU 核心数与内存物理页大小，把内存分配器、垃圾回收器、调度器逐一唤醒，最后才创建那个&#xA;承载 &lt;code&gt;main&lt;/code&gt; 的 goroutine，交由调度循环去运行。换言之，一个 Go 二进制文件里随身带着一个&#xA;微型操作系统（&lt;a href=&#34;../../ch01intro/go&#34;&gt;1.2&lt;/a&gt;），它先于用户代码自行启动。本节顺着这条引导链走一遍，&#xA;从操作系统的入口符号，到第一个 goroutine 被调度，看清楚「在 &lt;code&gt;main&lt;/code&gt; 之前」究竟发生了什么。&lt;/p&gt;&#xA;&lt;p&gt;引导链的脉络可以先记住三段：汇编入口在主线程上手工搭出 &lt;code&gt;g0&lt;/code&gt; 与 &lt;code&gt;m0&lt;/code&gt;（&lt;a href=&#34;/zh-cn/part1overview/ch03life/boot/#351-%e6%b1%87%e7%bc%96%e5%85%a5%e5%8f%a3g0m0-%e4%b8%8e-tls&#34;&gt;3.5.1&lt;/a&gt;），&#xA;&lt;code&gt;schedinit&lt;/code&gt; 按依赖次序点亮各个子系统（&lt;a href=&#34;/zh-cn/part1overview/ch03life/boot/#352-schedinit%e6%8c%89%e6%ac%a1%e5%ba%8f%e5%94%a4%e9%86%92%e8%bf%90%e8%a1%8c%e6%97%b6&#34;&gt;3.5.2&lt;/a&gt;），随后&#xA;&lt;code&gt;newproc&lt;/code&gt; 造出第一个 goroutine、&lt;code&gt;mstart&lt;/code&gt; 进入调度循环把它跑起来（&lt;a href=&#34;/zh-cn/part1overview/ch03life/boot/#353-%e7%ac%ac%e4%b8%80%e4%b8%aa-goroutine-%e4%b8%8e%e8%b0%83%e5%ba%a6%e5%be%aa%e7%8e%af&#34;&gt;3.5.3&lt;/a&gt;）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;351-汇编入口g0m0-与-tls&#34;&gt;3.5.1 汇编入口：g0、m0 与 TLS&lt;/h2&gt;&#xA;&lt;p&gt;运行时的真正入口由 runtime 包以汇编写就。以 AMD64 为例，Linux 与 macOS 的入口符号分别位于&#xA;&lt;code&gt;runtime/rt0_linux_amd64.s&lt;/code&gt; 与 &lt;code&gt;runtime/rt0_darwin_amd64.s&lt;/code&gt;，两者都只是一跳，转入共用的&#xA;&lt;code&gt;_rt0_amd64&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-asm&#34; data-lang=&#34;asm&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;TEXT&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;_rt0_amd64_linux&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;SB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;NOSPLIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$-8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;nf&#34;&gt;JMP&lt;/span&gt;&#x9;&lt;span class=&#34;no&#34;&gt;_rt0_amd64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;SB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;TEXT&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;_rt0_amd64_darwin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;SB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;NOSPLIT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;$-8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#x9;&lt;span class=&#34;nf&#34;&gt;JMP&lt;/span&gt;&#x9;&lt;span class=&#34;no&#34;&gt;_rt0_amd64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;SB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;为何按「架构 + 操作系统」两维拆分入口？因为程序编译为机器码后，指令集只取决于 CPU 架构，&#xA;而操作系统的差异体现在系统调用等系统级操作上。一份 &lt;code&gt;_rt0_amd64&lt;/code&gt; 可被多个操作系统共用，&#xA;各操作系统再以自己的入口符号跳进来。&lt;code&gt;rt0&lt;/code&gt; 是 &lt;code&gt;runtime0&lt;/code&gt; 的缩写，意指运行时的创生，&#xA;此后所有派生出来的同类对象都以 &lt;code&gt;1&lt;/code&gt; 为后缀，&lt;code&gt;g0&lt;/code&gt;、&lt;code&gt;m0&lt;/code&gt; 即得名于此。&lt;/p&gt;</description>
    </item>
    <item>
      <title>3.6 主 Goroutine 的生与死</title>
      <link>/zh-cn/part1overview/ch03life/main/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part1overview/ch03life/main/</guid>
      <description>&lt;h1 id=&#34;36-主-goroutine-的生与死&#34;&gt;3.6 主 Goroutine 的生与死&lt;/h1&gt;&#xA;&lt;p&gt;&lt;a href=&#34;.././boot&#34;&gt;3.5&lt;/a&gt; 里 &lt;code&gt;schedinit&lt;/code&gt; 把运行时的家底备齐之后并不直接调用 &lt;code&gt;runtime.main&lt;/code&gt;，而是把它&#xA;的入口地址压栈、交给 &lt;code&gt;newproc&lt;/code&gt; 造出第一个 Goroutine，再由 &lt;code&gt;mstart&lt;/code&gt; 启动调度循环、把这个&#xA;Goroutine 挑出来执行。调度的细节留到 &lt;a href=&#34;/zh-cn/part3concurrency/ch09sched/&#34;&gt;9 调度器&lt;/a&gt; 详谈，本节&#xA;只把镜头对准一个时刻：&lt;strong&gt;第一个 Goroutine 已经在跑，它正要执行 &lt;code&gt;runtime.main&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这只 Goroutine 与众不同。它是程序里诞生的第一个，承载着用户的 &lt;code&gt;main.main&lt;/code&gt;，也独自掌握着整个&#xA;进程的生杀大权：它一返回，进程就结束，哪怕别处还有上千个 Goroutine 正忙。理解它做了什么、&#xA;以及它何时收手，是理解「一个 Go 程序如何开始、又如何整体退出」的最后一块拼图。&lt;/p&gt;&#xA;&lt;h2 id=&#34;361-runtimemain用户代码之前的铺垫&#34;&gt;3.6.1 &lt;code&gt;runtime.main&lt;/code&gt;：用户代码之前的铺垫&lt;/h2&gt;&#xA;&lt;p&gt;运行时包里的 &lt;code&gt;main&lt;/code&gt; 函数（即 &lt;code&gt;runtime.main&lt;/code&gt;）与用户的 &lt;code&gt;main.main&lt;/code&gt; 跑在同一个 Goroutine 上，&#xA;但在把控制权交给用户之前，它先料理了几桩只能由「第一个 Goroutine」来做的事。下面是裁剪后的&#xA;速写，只留与生命周期相关的骨架：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;21&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;22&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;23&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;24&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;25&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;26&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;27&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;28&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;29&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;30&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;31&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;32&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;33&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;34&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;35&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;36&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;37&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;38&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;39&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;40&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;41&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;42&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;43&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;44&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;45&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;46&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 主 Goroutine 入口（裁剪自 runtime/proc.go）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;getg&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 执行栈上限：64 位 1GB，32 位 250MB（用十进制，崩溃信息里更好看）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;goarch&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;PtrSize&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;maxstacksize&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1000000000&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;maxstacksize&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;250000000&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mainStarted&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 允许 newproc 启动新的 M&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;haveSysmon&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 启动系统监控线程（见 9.8）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;systemstack&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;newm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sysmon&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;lockOSThread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 初始化期间把主 G 锁在主 OS 线程上&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mp&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;throw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;runtime.main not on m0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtimeInitTime&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;nanotime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 记下「世界开始」的时刻，须在 doInit 之前&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;doInit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtime_inittasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 运行运行时自身的 init（含 GC、defer 类型等）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;gcenable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 启用垃圾回收器（见 13）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 按依赖顺序运行所有模块（含用户包）的 init 任务&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lastmoduledatap&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;firstmoduledata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;doInit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;inittasks&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;==&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;unlockOSThread&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;main_main&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;               &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 间接调用：链接器此时不知道 main 包的地址&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                       &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 主 G 一返回，整个进程退出&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这段骨架里有几处值得停下来看。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
