GOEXPERIMENT 用法与 Go 1.26 实验清单:默认关闭项怎么开,默认开启项怎么用 no 前缀回退
原文:Alex Edwards, "Go Experiments Explained", June 1, 2026 — alexedwards.net
中文译版:colobu.com
相关源码:src/internal/goexperiment/flags.go、src/internal/buildcfg/exp.go
实验特性是什么
Go 在发布新版本时经常会附带实验性特性(experimental features)。这些实验性特性有不同的形式:有时是标准库中全新的包,有时是编译器或运行时的改动,偶尔也可能是对 Go 行为的破坏性变更。
大多数情况下,实验性特性的目的是在某个功能正式进入通用可用(general availability)阶段、成为 Go 的永久组成部分之前,从用户那里获取真实世界的反馈。如果该特性导致性能退化,或收到社区的负面反馈,它可以在最终定稿前被修改——甚至被完全放弃。
近期几个例子
- Go 1.24 发布时附带了新的
testing/synctest包的实验性支持(测试并发代码)。收到反馈后 API 略有调整,Go 1.25 正式 GA。 - Go 1.25 发布时附带了新的垃圾回收器设计的实验性支持,性能更好。吸收反馈后,新 GC 在 Go 1.26 成为默认。
- Go 1.21 发布时附带了循环变量语义行为变更的实验性支持,消除历史 bug,但技术上是对语言的破坏性变更。作为实验发布让人们在 Go 1.22 默认之前有机会测试。
实验特性的生命周期
大多数实验特性最初以默认关闭(off-by-default)方式发布。需要显式 opt-in 试用,通常设置 GOEXPERIMENT 环境变量。如果一切顺利,经过一到两个版本后 GA 并变为默认开启。如果实验特性影响了某些行为,GA 后有时(但并非总是)会有过渡宽限期,可临时禁用并用旧行为。例如 Go 1.26 中新的 GC 设计 GA 且默认开启,但需要时仍可禁用并回退旧 GC。
也有的更漫长:Go 1.22 附带的编译器内联逻辑实验实现,两年多后仍默认关闭、处于评估中。同一次发布还附带内存 arena 实验,收到负面反馈后仍默认关闭、无限期搁置,最终可能被完全移除。
当 Go 团队对某个变更足够有信心时,可能跳过反馈阶段直接 GA,但仍保留过渡宽限期。例如 Go 1.24 把 map 实现改为 Swiss tables,直接 GA 并默认开启,但至少目前仍可退出并使用旧 map 实现。
实践上实验特性有三种大致状态:默认关闭评估中;默认关闭搁置/休眠中;默认开启但有临时退出选项。
永久实验特性
Go 还有一些实验性功能并非通常意义上的“实验”。默认关闭,但不在评估中、不在寻求反馈、也没有预期 GA 变默认。它们通过 GOEXPERIMENT 控制,更像特定场景下的可选 Go 功能。例如 field tracking 诊断功能(追踪哪些结构体字段被访问),已存在十年且没有意图 GA;static lock ranking(查找 Go 运行时潜在死锁的诊断工具)。
当前有哪些可用的实验特性
很难知道。Go 官方文档或 Go Wiki 没有页面追踪实验特性状态。要自己搞清楚可以:
- 运行
$ go doc goexperiment.Flags获取所有可用实验的列表。 - 阅读
src/internal/buildcfg/exp.go源码,特别关注ParseGOEXPERIMENT()函数中的baseline变量声明,找出哪些实验默认开启。 - 将实验名称与 Go 发布说明交叉对照,搜索 GitHub issues 判断当前状态。
截至 Go 1.26:永久实验特性
- FieldTrack:追踪哪些结构体字段被访问的诊断工具。默认关闭,永久存在。
- StaticLockRanking:验证锁获取顺序以捕获死锁的诊断工具。默认关闭,永久存在。
- CgoCheck2:检查 cgo 指针传递规则的诊断工具;运行时开销太大不适合默认开。默认关闭,永久存在。
- BoringCrypto:用 FIPS 认证的 BoringSSL 替换 Go 的 crypto;自 Go 1.24 起已不再需要。默认关闭,永久存在,但很快将被移除。
- PreemptibleLoops:允许调度器在循环回边处抢占 goroutine;自 Go 1.14 起通常不再需要,但在不支持抢占的平台上可能仍有用。默认关闭,永久存在。
当前默认关闭的实验特性及其状态
- HeapMinimum512KiB:将最小堆大小从 4MB 减少到 512KiB;可能在受限环境中有用。默认关闭,可能已休眠。
- Arenas:内存 arena 实现。默认关闭,收到负面反馈后已搁置。
- NewInliner:重写的编译器内联器,更好的调用点启发式算法。默认关闭,评估中(自 Go 1.22 起可用)。
- JSONv2:新的
encoding/json/v2包,提供改进的 JSON 编码/解码函数。默认关闭,评估中(自 Go 1.25 起可用)。 - RuntimeSecret:新的
runtime/secret包,提供清零内存的函数;仅支持 Linux amd64/arm64。默认关闭,评估中(自 Go 1.26 起可用)。 - GoroutineLeakProfile:新增
goroutineleakpprof 分析类型。默认关闭,评估中(自 Go 1.26 起可用)。 - SIMD:新的
simd/archsimd包,提供对架构特定 SIMD 操作的访问;仅支持 amd64。默认关闭,评估中(自 Go 1.26 起可用)。 - RuntimeFreegc:在安全时允许立即重用内存而无需等待 GC 周期。默认关闭,评估中(自 Go 1.26 起可用,状态见 #74299)。
- SizeSpecializedMalloc:启用按大小类别特化的 malloc 实现。默认关闭,评估中(自 Go 1.26 起可用,状态见 #74299)。
当前默认开启的实验特性
- LoopVar:每次迭代独立的循环变量作用域。自 Go 1.22 起默认开启,但为边缘情况保留退出选项。
- Dwarf5:DWARF 5 调试信息生成;减小二进制文件大小。默认开启,保留临时退出选项(可能在未来版本移除)。
- RandomizedHeapBase64:启动时随机化堆基址,作为安全措施。默认开启,保留临时退出选项(预计未来版本移除)。
- GreenTeaGC:新的垃圾回收器,性能更好;在 darwin/ios/aix 上不可用。默认开启,保留临时退出选项(预计在 Go 1.27 中移除退出选项)。
- RegabiWrappers:用于在 ABI0 和 ABIInternal 函数之间调用的 ABI 包装器;仅支持 64 位架构。默认开启,临时退出选项仅对 s390x 有效,且将在 Go 1.27 中移除。
- RegabiArgs:在所有编译的 Go 函数中启用寄存器参数/返回值;仅支持 64 位架构。默认开启,临时退出选项仅对 s390x 有效,且将在 Go 1.27 中移除。
如何启用和禁用实验特性
通过 GOEXPERIMENT 环境变量控制。
尝试默认关闭的实验特性,把实验名称作为逗号分隔的小写值放进 GOEXPERIMENT:
$ GOEXPERIMENT=jsonv2,goroutineleakprofile go build ./...
关闭某个默认开启的实验特性,在小写名称前加 no 前缀:
$ GOEXPERIMENT=nogreenteagc,norandomizedheapbase64 go build ./...
混合启用和禁用也没问题:
$ GOEXPERIMENT=jsonv2,nogreenteagc go build ./...
注意:如果用不同 GOEXPERIMENT 值构建同一个包,Go 会把它们视为不同的构建,并在构建缓存中存储独立条目。go build 的用法在 go run / go test 上同样适用。
用实验性 encoding/json/v2 包
package main
import (
"encoding/json/v2"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
City string `json:"city"`
}
func main() {
p := Person{Name: "Ada", Age: 36, City: "Vienna"}
data, _ := json.Marshal(p, json.StringifyNumbers(true))
fmt.Println(string(data))
}
正常运行此程序将无法编译:
$ go run main.go
package command-line-arguments
imports encoding/json/v2: build constraints exclude all Go files in /usr/local/go/src/encoding/json/v2
启用 JSONv2 实验后按预期运行:
$ GOEXPERIMENT=jsonv2 go run main.go
{"name":"Ada","age":"36","city":"Vienna"}
普通 Gopher 该关注哪些实验特性
如果你主要用 Go 写程序而非开发 Go 本身,大多数实验特性关系不大。最相关的几个:
- GreenTeaGC:用 Go 1.26 已在默认使用。若发现性能或行为问题,仍可禁用它(并应提交 issue)。
- Dwarf5:Go 1.25 及以上已默认使用。遇到问题仍可禁用它。
- JSONv2:不建议在 GA 之前切换,但若编写大量 JSON 代码,值得试新的
encoding/json/v2,熟悉即将到来的内容并反馈。 - GoroutineLeakProfile:若怀疑 goroutine 泄漏需要调试,值得启用。
- RuntimeSecret:若编写加密代码或处理敏感数据,值得尝试并反馈。
- RuntimeFreegc:若应用严重依赖 GC,可能值得启用并做基准测试,看是否提升性能并反馈。
兼容性警告
实验特性不受 Go 兼容性承诺覆盖。其 API、行为和性能特征都可能变化,通常最好避免过早采用,不要在实验特性最终定稿前依赖它们。但实验特性通常是对 Go 中一些重大变更的预览。若知道某实验 GA 并默认开启后可能影响你或你的代码,尝试它、酌情跑基准、发现问题就反馈是好做法。Go 发布说明最近在记录实验特性及其使用方式方面越来越好。