Go 1.27 让 80 字节以内的分配快了 20–30%,代价是 icache
Go 1.27 让 80 字节及以下的分配获得了更快的内存分配。 这类分配最多可快 20-30%,使分配密集的程序最多快 1%。 Go 运行时通过引入特化函数来提升这些分配的性能, 这些函数专门用于分配特定尺寸。
中文
复制
The Go Blog
尺寸特化的内存分配
Michael Matloob
2026 年 9 月 16 日
Go 1.27 让 80 字节及以下的分配获得了更快的内存分配。
这类分配最多可快 20-30%,使分配密集的程序最多快 1%。
Go 运行时通过引入特化函数来提升这些分配的性能,
这些函数专门用于分配特定尺寸。经过特化,函数就能做出某些假设,
从而更快,也更容易优化。
这篇博文将解释它的原理,以及它如何让你的程序更快。
堆分配由运行时的 mallocgc 函数创建,它需要知道分配的大小以及其中是否包含指针。当编译器判定某个对象逃逸到堆上,或者需要动态分配时,
它会插入一个对 newobject 的调用,后者是一个简单的包装函数,负责取出对象的大小以及是否包含指针,并把它们传给 mallocgc。
这两项信息决定了分配器要做的大部分工作。大小之所以重要,是因为分配器
定义了一系列尺寸区间,称为“尺寸类”。对于大多数既不太大也不太小的分配,
它会从一个空闲对象列表中返回一块内存,这些对象的大小都等于该尺寸类的上限。比如尺寸类 3
是 17-24 字节。所以无论你分配 17 字节还是 24 字节,分配器都会从它的 24 字节对象列表中
把下一个空闲的 24 字节对象给你。
下面是 80 字节以内各个尺寸类的尺寸区间表。
空闲列表分为两套,我们称之为 span,具体取决于分配是否包含指针,
因为垃圾回收器需要做相应的记账。
| 尺寸类 | 尺寸区间 |
|---|---|
1 | 1-8 字节 |
2 | 9-16 字节 |
3 | 17-24 字节 |
4 | 25-32 字节 |
5 | 33-48 字节 |
6 | 49-64 字节 |
7 | 65-80 字节 |
由于分配的大小类别以及其中是否包含指针,共同决定了我们从哪个 span 分配内存,因此分配器有一个叫做 span class 的类型,其取值同时编码了这两者:它被定义为 `sizeClass
上一篇文章:Goroutine 泄漏画像