<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>内存布局 on Zampo Blog</title><link>https://blog.cpdd.fyi/tags/%E5%86%85%E5%AD%98%E5%B8%83%E5%B1%80/</link><description>Recent content in 内存布局 on Zampo Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sat, 23 May 2026 09:45:00 +0800</lastBuildDate><atom:link href="https://blog.cpdd.fyi/tags/%E5%86%85%E5%AD%98%E5%B8%83%E5%B1%80/index.xml" rel="self" type="application/rss+xml"/><item><title>Go 里真正难懂的不是 slice，是它背后的数组</title><link>https://blog.cpdd.fyi/posts/go-array-slice-design/</link><pubDate>Sat, 23 May 2026 09:45:00 +0800</pubDate><guid>https://blog.cpdd.fyi/posts/go-array-slice-design/</guid><description>&lt;p&gt;一次 &lt;code&gt;append&lt;/code&gt;，把原来的数据改坏了。&lt;/p&gt;
&lt;p&gt;代码看起来很普通：从一个 slice 里切一段出来，往这段里追加一个元素。你以为只是改了新变量，结果回头一看，原 slice 里的某个位置也变了。&lt;/p&gt;
&lt;p&gt;这类问题很烦，因为它不像空指针那样直接炸给你看。它更像一个安静的错：数据还在，长度也对，测试偶尔过，线上某个分支才露出一点不对劲。&lt;/p&gt;
&lt;p&gt;很多人这时会说：slice 是引用类型。&lt;/p&gt;
&lt;p&gt;这句话不算完全错，但太粗糙。粗糙到一定程度，就会害人。&lt;/p&gt;
&lt;p&gt;Go 里真正值得理解的，不是“slice 是不是引用类型”，而是：数组负责装数据，slice 只负责描述一段数组。数组给机器确定性，slice 给程序员弹性。Go 同时保留这两个东西，不是语言设计多此一举，而是它不愿意把这两种需求混成一团。&lt;/p&gt;
&lt;p&gt;理解这一点，后面的 &lt;code&gt;append&lt;/code&gt;、扩容、子切片、内存保留，都会变得顺很多。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.cpdd.fyi/images/go-array-slice-design/array-vs-slice-layout.png" alt="数组和 slice 的内存布局"&gt;&lt;/p&gt;
&lt;h2 id="数组很硬但这正是它的价值"&gt;数组很硬，但这正是它的价值&lt;/h2&gt;
&lt;p&gt;Go 的数组不是“指向一串元素的地址”。数组变量代表的是整个数组。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[3]int&lt;/code&gt; 和 &lt;code&gt;[4]int&lt;/code&gt; 是两个不同类型。长度进类型，元素连续排列，赋值和传参都会复制整个数组。这些特性放到业务代码里看，确实不够灵活：函数想接收任意长度的整数列表，不能写一个 &lt;code&gt;[N]int&lt;/code&gt; 让 N 动起来；大数组传来传去，也会带来复制成本。&lt;/p&gt;
&lt;p&gt;但站在机器这边看，数组非常舒服。&lt;/p&gt;
&lt;p&gt;长度确定，布局连续，元素类型一致。编译器知道它有多大，CPU 也喜欢顺着连续内存往前读。很多时候，所谓“底层性能”，并不是某个神秘技巧，而是数据摆得足够朴素，机器不用猜。&lt;/p&gt;
&lt;p&gt;所以数组不是 Go 里被 slice 淘汰掉的旧家具。它更像地基。&lt;/p&gt;
&lt;p&gt;你日常很少把数组当动态集合用，不代表它不重要。恰恰相反，slice 的一切便利，都建立在底层数组这块“确定形状的钢板”上。&lt;/p&gt;
&lt;h2 id="slice-不是数组是一张小纸条"&gt;slice 不是数组，是一张小纸条&lt;/h2&gt;
&lt;p&gt;slice 本身并不装元素。&lt;/p&gt;
&lt;p&gt;在 Go 1.25.4 的 runtime 源码里，slice 的核心结构就是三个字段：&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;/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;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;slice&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;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;unsafe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pointer&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;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&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;cap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&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;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;可以把它理解成一张小纸条：&lt;/p&gt;</description></item></channel></rss>