Go 1.25正式发布
最新的 Go 版本 1.25 于 2025 年 8 月发布,距离 Go 1.24 间隔六个月。其大部分变化集中在工具链、运行时和库的实现上。与往常一样,该版本保持了 Go 1 的兼容性承诺。我们预计几乎所有 Go 程序都能像以前一样继续编译和运行。
语言变化
Go 1.25 中没有影响 Go 程序的语言变化。不过,在语言规范中,“核心类型” 的概念已被移除,取而代之的是专门的描述文字。更多信息请参见相关博客文章。
工具
Go 命令
go build -asan
选项现在默认在程序退出时进行内存泄漏检测。如果 C 分配的内存未被释放,且未被 C 或 Go 分配的任何其他内存引用,将会报告错误。运行程序时,可通过设置环境变量 ASAN_OPTIONS=detect_leaks=0
禁用这些新的错误报告。
Go 发行版将包含更少的预构建工具二进制文件。核心工具链二进制文件(如编译器和链接器)仍会包含,但 go tool
不会再预构建那些不被构建或测试操作调用的工具,而是会根据需要动态构建和运行它们。
新的 go.modignore
指令可用于指定命令应忽略的目录。这些目录及其子目录中的文件在匹配包模式(如 go all
或 ./...
)时会被命令忽略,但仍会包含在模块压缩文件中。
新的 go doc -http
选项会启动一个文档服务器,显示请求对象的文档,并在浏览器窗口中打开该文档。
新的 go version -m -json
选项会打印嵌入在给定 Go 二进制文件中的 runtime/debug.BuildInfo
结构的 JSON 编码。
当使用 <meta name="go-import" content="root-path vcs repo-url subdir">
语法解析模块路径时,go
命令现在支持将仓库的子目录用作模块根目录,其中 root-path
对应 vcs
版本控制系统中 repo-url
的 subdir
。
新的 work
包模式匹配工作模块(以前称为主模块)中的所有包:在模块模式下为单个工作模块,在工作区模式下为一组工作区模块。
当 go
命令更新 go.mod
或 go.work
文件中的 go
行时,不再添加指定命令当前版本的工具链行。
Vet
go vet
命令包含新的分析器:
waitgroup
:报告sync.WaitGroup.Add
的错误调用位置;hostport
:报告使用fmt.Sprintf("%s:%d", host, port)
构建net.Dial
地址的情况(这些地址在 IPv6 下无法工作),并建议使用net.JoinHostPort
。
运行时
感知容器的 GOMAXPROCS
GOMAXPROCS
的默认行为已更改。在早期 Go 版本中,GOMAXPROCS
默认值为启动时可用的逻辑 CPU 数量(runtime.NumCPU
)。Go 1.25 引入了两项变化:
在 Linux 上,运行时会考虑包含该进程的 cgroup 的 CPU 带宽限制(如果有)。如果 CPU 带宽限制低于可用的逻辑 CPU 数量,GOMAXPROCS
默认值会设为较低的限制。在 Kubernetes 等容器运行时系统中,cgroup CPU 带宽限制通常对应 “CPU 限制” 选项。Go 运行时不考虑 “CPU 请求” 选项。
在所有操作系统上,如果可用逻辑 CPU 数量或 cgroup CPU 带宽限制发生变化,运行时会定期更新 GOMAXPROCS
。
如果通过环境变量或调用 runtime.GOMAXPROCS
手动设置了 GOMAXPROCS
,上述两种行为都会自动禁用。也可分别通过 GODEBUG
设置 containermaxprocs=0
和 updatemaxprocs=0
显式禁用它们。
为了支持读取更新的 cgroup 限制,运行时会在进程生命周期内缓存 cgroup 文件的文件描述符。
新的实验性垃圾收集器
现在有一个新的垃圾收集器作为实验特性可用。该垃圾收集器的设计通过更好的局部性和 CPU 可扩展性,提高了标记和扫描小对象的性能。基准测试结果各不相同,但我们预计在重度使用垃圾收集器的实际程序中,垃圾收集开销会减少 10% - 40%。
可在构建时通过设置 GOEXPERIMENT=greenteagc
启用新的垃圾收集器。我们预计其设计会继续演进和改进。为此,我们鼓励 Go 开发者尝试使用并反馈体验。更多设计细节和反馈说明请参见 GitHub issue。
Trace flight recorder¶
长期以来,运行时执行跟踪提供了一种强大但开销较大的方式,用于理解和调试应用程序的底层行为。但由于其体积较大且持续写入执行跟踪的成本较高,通常难以用于调试罕见事件。
新的 runtime/trace.FlightRecorder
API 提供了一种轻量级的方式来捕获运行时执行跟踪:它会持续将跟踪记录到内存中的环形缓冲区。当发生重要事件时,程序可调用 FlightRecorder.WriteTo
将最近几秒的跟踪快照写入文件。这种方式通过让应用程序只捕获关键跟踪,生成的跟踪文件小得多。
FlightRecorder
捕获的时间长度和数据量可在 FlightRecorderConfig
中配置。
未处理恐慌输出的变化
当程序因未处理的恐慌(已恢复并再次恐慌)退出时,打印的消息不再重复恐慌值的文本。
以前,一个程序若因 panic("PANIC")
恐慌、恢复恐慌后又用原始值再次恐慌,会打印:
plaintext
panic: PANIC [recovered]panic: PANIC
现在该程序会打印:
plaintext
panic: PANIC [recovered, repanicked]
Linux 上的 VMA 名称
在支持匿名虚拟内存区域(VMA)名称的 Linux 系统(CONFIG_ANON_VMA_NAME
)上,Go 运行时会为匿名内存映射添加用途相关的上下文标注。例如,堆内存会标注为 [anon: Go: heap]
。可通过 GODEBUG=decoratemappings=0
禁用此功能。
编译器
空指针漏洞
此版本修复了 Go 1.21 中引入的一个编译器漏洞,该漏洞可能错误地延迟空指针检查。如下程序以前能(错误地)成功执行,现在会(正确地)因空指针异常恐慌:
go
package mainimport "os"func main() {f, err := os.Open("nonExistentFile")name := f.Name()if err != nil {return}println(name)
}
该程序存在问题,因为它在检查错误之前使用了 os.Open
的结果。如果 err
非空,f
可能为 nil,此时 f.Name()
应恐慌。但在 Go 1.21 到 1.24 版本中,编译器错误地将空检查延迟到错误检查之后,导致程序违反 Go 规范却能成功执行。在 Go 1.25 中,它将不再成功运行。如果此变化影响了你的代码,解决方法是将非空错误检查放在代码中更早的位置,最好是在生成错误的语句之后。
DWARF5 支持
Go 1.25 中的编译器和链接器现在使用 DWARF 版本 5 生成调试信息。较新的 DWARF 版本减少了 Go 二进制文件中调试信息所需的空间,并缩短了链接时间(尤其是大型 Go 二进制文件)。可在构建时通过设置环境变量 GOEXPERIMENT=nodwarf5
禁用 DWARF 5 生成(此回退选项可能在未来版本中移除)。
更快的切片
编译器现在能在更多情况下在栈上分配切片的底层存储,从而提高性能。此变化可能会放大不正确的 unsafe.Pointer
使用带来的影响(例如 issue 73199)。为了追踪这些问题,可使用 bisect
工具并通过 -compile=variable
标志查找有问题的分配。也可通过 make -gcflags=all=-d=variablehash=n
关闭所有此类新的栈分配。
链接器
链接器现在接受 funcalign=N
命令行选项,用于指定函数入口的对齐方式。默认值取决于平台,本版本中未改变。
标准库
新的 testing/synctest 包
新的 testing/synctest
包为测试并发代码提供支持。
Test
函数在隔离的 “气泡” 中运行测试函数。在气泡内,时间是虚拟化的:time
包函数基于虚拟时钟运行,且如果气泡中的所有 goroutine 都处于阻塞状态,时钟会瞬间向前推进。
Wait
函数等待当前气泡中的所有 goroutine 阻塞。
该包最初在 Go 1.24 中以 GOEXPERIMENT=synctest
形式提供,API 略有不同。现在该实验已毕业并正式可用。如果设置了 GOEXPERIMENT=synctest
,旧 API 仍然存在,但会在 Go 1.26 中移除。
新的实验性 encoding/json/v2 包
Go 1.25 包含一个新的实验性 JSON 实现,可在构建时通过设置环境变量 GOEXPERIMENT=jsonv2
启用。
启用后,有两个新包可用:
encoding/json/v2
包:encoding/json
包的重大修订版。encoding/json/jsontext
包:提供 JSON 语法的底层处理。
此外,当启用 “jsonv2” GOEXPERIMENT 时:
encoding/json
包使用新的 JSON 实现。序列化和反序列化行为不受影响,但包函数返回的错误文本可能会变化。encoding/json
包包含许多可用于配置序列化器和反序列化器的新选项。
在许多场景下,新实现的性能显著优于现有实现。一般来说,两者的序列化性能相当,而新实现的反序列化性能明显更快。更多详细分析请参见 github.com/go-json-experiment/jsonbench
仓库。
更多细节请参见提案 issue。
我们鼓励 encoding/json
的用户在启用 GOEXPERIMENT=jsonv2
的情况下测试他们的程序,以帮助发现与新实现的兼容性问题。
我们预计 encoding/json/v2
的设计会继续演进。鼓励开发者尝试新 API 并在提案 issue 上提供反馈。
库的次要变化
archive/tar
Writer.AddFS
实现现在支持实现 io/fs.ReadLinkFS
的文件系统的符号链接。
encoding/asn1
Unmarshal
和 UnmarshalWithParams
现在更一致地解析 ASN.1 类型 T61String
和 BMPString
。这可能导致一些以前被接受的格式错误的编码现在被拒绝。
crypto
MessageSigner
是一个新的签名接口,可由希望自行对要签名的消息进行哈希的签名者实现。还引入了新函数 SignMessage
,它尝试将 Signer
接口升级为 MessageSigner
,如果成功则使用 MessageSigner.SignMessage
方法,否则使用 Signer.Sign
。当代码希望同时支持 Signer
和 MessageSigner
时,可使用此函数。
程序启动后更改 GODEBUG
的 fips140
设置现在无效。以前,文档中注明不允许这样做,且更改可能导致恐慌。
在 amd64 上,当不支持 AVX2 指令时,SHA-1、SHA-256 和 SHA-512 现在更慢。2015 年以后生产的所有服务器处理器(以及大多数其他处理器)都支持 AVX2。
crypto/ecdsa
新的 ParseRawPrivateKey
、ParseUncompressedPublicKey
、PrivateKey.Bytes
和 PublicKey.Bytes
函数及方法实现了底层编码,无需再使用 crypto/elliptic
或 math/big
的函数和方法。
当启用 FIPS 140-3 模式时,签名速度现在提高了四倍,与非 FIPS 模式的性能相当。
crypto/ed25519
当启用 FIPS 140-3 模式时,签名速度现在提高了四倍,与非 FIPS 模式的性能相当。
crypto/elliptic
某些 Curve
实现上隐藏且未文档化的 Inverse
和 CombinedMult
方法已被移除。
crypto/rsa
PublicKey
不再声称模数是保密的。VerifyPKCS1v15
和 VerifyPSS
早已警告所有输入都是公开的且可能被泄露,并且有一些数学攻击可以从其他公开值中恢复模数。
密钥生成现在快了三倍。
crypto/sha1
在 amd64 上,当支持 SHA-NI 指令时,哈希速度现在快了两倍。
crypto/sha3
新的 SHA3.Clone
方法实现了 hash.Cloner
。
在 Apple M 处理器上,哈希速度现在快了两倍。
crypto/tls
新的 ConnectionState.CurveID
字段公开了用于建立连接的密钥交换机制。
新的 Config.GetEncryptedClientHelloKeys
回调可用于为服务器设置加密客户端问候(Encrypted Client Hello)扩展的 EncryptedClientHelloKeys
。
根据 RFC 9155,TLS 1.2 握手现在禁止使用 SHA-1 签名算法。可通过 GODEBUG=tlssha1=1
重新启用。
当启用 FIPS 140-3 模式时,TLS 1.2 现在要求使用扩展主密钥(Extended Master Secret),且允许使用 Ed25519 和 X25519MLKEM768。
TLS 服务器现在优先选择最高支持的协议版本,即使它不是客户端最偏好的协议版本。
TLS 客户端和服务器现在在遵循规范和拒绝非规范行为方面更加严格。与合规对等方的连接应不受影响。
crypto/x509
CreateCertificate
、CreateCertificateRequest
和 CreateRevocationList
现在可接受 crypto.MessageSigner
签名接口以及 crypto.Signer
。这允许这些函数使用实现 “一次性” 签名接口的签名者,其中哈希由签名操作本身完成,而非调用者。
CreateCertificate
现在在 SubjectKeyId
缺失时使用截断的 SHA-256 来填充。GODEBUG=x509sha256skid=0
设置可恢复为使用 SHA-1。
ParseCertificate
现在拒绝包含 BasicConstraints 扩展且 pathLenConstraint 为负数的证书。
ParseCertificate
现在更一致地处理使用 ASN.1 T61String 和 BMPString 类型编码的字符串。这可能导致一些以前被接受的格式错误的编码现在被拒绝。
debug/elf
debug/elf
包添加了两个新常量:
PT_RISCV_ATTRIBUTES
- 用于 RISC-V ELF 解析的
SHT_RISCV_ATTRIBUTES
go/ast
FilterPackage
、PackageExports
、MergePackageFiles
函数,以及 MergeMode
类型及其常量均已弃用,因为它们仅用于早已弃用的 Object 和 Package 机制。
新的 PreorderStack
函数与 Inspect
类似,会遍历语法树并提供对子树遍历的控制,此外还方便地在每个节点处提供封闭节点的栈。
go/parser
ParseDir
函数已弃用。
go/token
新的 FileSet.AddExistingFiles
方法允许将现有 File
添加到 FileSet
,或为任意一组 File
构建 FileSet
,从而缓解长期运行的应用程序中单个全局 FileSet
带来的问题。
go/types
Var
现在有一个 Var.Kind
方法,将变量分类为以下之一:包级变量、接收器、参数、返回值、局部变量或结构体字段。
新的 LookupSelection
函数查找给定名称和接收器类型的字段或方法,与现有的 LookupFieldOrMethod
函数类似,但返回 Selection
形式的结果。
hash
新的 XOF
接口可由 “可扩展输出函数”(XOF)实现,这些函数是具有任意或无限输出长度的哈希函数,如 SHAKE。
实现新 Cloner
接口的哈希可以返回其状态的副本。所有标准库哈希实现现在都实现了 Cloner
。
hash/maphash
新的 Hash.Clone
方法实现了 hash.Cloner
。
io/fs
新的 ReadLinkFS
接口提供读取文件系统中符号链接的能力。
log/slog
GroupAttrs
从 Attr
值切片创建一个组 Attr
。
Record
现在有一个 Source
方法,返回其源位置或 nil(如果不可用)。
mime/multipart
新的辅助函数 FileContentDisposition
构建多部分 Content-Disposition
头字段。
net
LookupMX
和 Resolver.LookupMX
现在返回看起来像有效 IP 地址的 DNS 名称以及有效域名。以前,如果名称服务器返回 IP 地址作为 DNS 名称,LookupMX
会按照 RFC 要求丢弃它。但实际上,名称服务器有时确实会返回 IP 地址。
在 Windows 上,ListenMulticastUDP
现在支持 IPv6 地址。
在 Windows 上,现在可以在 os.File
和网络连接之间进行转换。具体来说,FileConn
、FilePacketConn
和 FileListener
函数现已实现,返回与打开文件对应的网络连接或监听器。类似地,TCPConn
、UDPConn
、UnixConn
、IPConn
、TCPListener
和 UnixListener
的 File
方法现已实现,返回网络连接的底层 os.File
。
net/http
新的 CrossOriginProtection
通过拒绝不安全的跨域浏览器请求来实现对跨站请求伪造(CSRF)的保护。它使用现代浏览器的 Fetch 元数据,不需要令牌或 cookie,并支持基于源和模式的绕过。
os
在 Windows 上,NewFile
现在支持为异步 I/O 打开的句柄(即 syscall.CreateFile
调用中指定了 syscall.FILE_FLAG_OVERLAPPED
)。这些句柄与 Go 运行时的 I/O 完成端口相关联,这为生成的 File
带来以下好处:
- I/O 方法(
File.Read
、File.Write
、File.ReadAt
和File.WriteAt
)不会阻塞 OS 线程。 - 支持截止时间方法(
File.SetDeadline
、File.SetReadDeadline
和File.SetWriteDeadline
)。
此增强对在 Windows 上通过命名管道通信的应用程序特别有益。
请注意,一个句柄一次只能与一个完成端口相关联。如果提供给 NewFile
的句柄已与完成端口相关联,返回的 File
会降级为同步 I/O 模式。在这种情况下,I/O 方法会阻塞 OS 线程,且截止时间方法无效。
DirFS
和 Root.FS
返回的文件系统实现了新的 io/fs.ReadLinkFS
接口。CopyFS
在复制实现 io/fs.ReadLinkFS
的文件系统时支持符号链接。
Root
类型支持以下附加方法:
Root.Chmod
、Root.Chown
、Root.Chtimes
、Root.Lchown
、Root.Link
、Root.MkdirAll
、Root.ReadFile
、Root.Readlink
、Root.RemoveAll
、Root.Rename
、Root.Symlink
、Root.WriteFile
reflect
新的 TypeAssert
函数允许将 Value
直接转换为给定类型的 Go 值。这类似于对 Value.Interface
的结果使用类型断言,但避免了不必要的内存分配。
regexp/syntax
\p{name}
和 \P{name}
字符类语法现在接受名称 Any
、ASCII
、Assigned
、Cn
和 LC
,以及 Unicode 类别别名(如 \p{Letter}
对应 \pL
)。根据 Unicode TR18,它们现在还使用不区分大小写的名称查找,忽略空格、下划线和连字符。
runtime
AddCleanup
调度的清理函数现在并发且并行执行,这使得清理更适合频繁使用(如 unique
包)。请注意,如果个别清理操作必须执行长时间任务或阻塞,仍应将其工作分流到新的 goroutine,以避免阻塞清理队列。
新的 GODEBUG=checkfinalizers=1
设置有助于发现终结器和清理操作的常见问题(如 GC 指南中描述的那些)。在此模式下,运行时在每个垃圾收集周期运行诊断,并定期向 stderr 报告终结器和清理队列长度,以帮助识别长时间运行的终结器和 / 或清理操作的问题。更多细节请参见 GODEBUG
文档。
新的 SetDefaultGOMAXPROCS
函数将 GOMAXPROCS
设置为运行时默认值,就像未设置环境变量一样。如果 GOMAXPROCS
已被环境变量或之前的 GOMAXPROCS
调用禁用,此函数有助于启用新的 GOMAXPROCS
默认行为。
runtime/pprof
关于运行时内部锁争用的互斥锁概要文件现在正确指向导致延迟的临界区末尾。这与针对 sync.Mutex
值争用的概要文件行为一致。GODEBUG
中用于 runtimecontentionstacks
的设置(允许选择 Go 1.22 到 1.24 中此部分概要文件的特殊行为)现已移除。
sync
新的 WaitGroup.Go
方法使创建和计数 goroutine 的常见模式更便捷。
testing
T.Attr
、B.Attr
和 F.Attr
新方法向测试日志输出一个属性。属性是与测试相关联的任意键值对。
例如,在名为 TestF
的测试中,t.Attr("key", "value")
输出:
plaintext
=== ATTR TestF key value
使用 -json
标志时,属性会以新的 “attr” 动作出现。
T
、B
和 F
的新 Output
方法提供一个 io.Writer
,其输出写入与 TB.Log
相同的测试输出流。与 TB.Log
一样,输出会缩进,但不包含文件和行号。
如果并行测试正在运行,AllocsPerRun
函数现在会恐慌。如果有其他测试在运行,AllocsPerRun
的结果本质上是不稳定的。新的恐慌行为有助于发现此类错误。
testing/fstest
MapFS
实现了新的 io/fs.ReadLinkFS
接口。TestFS
会验证 io/fs.ReadLinkFS
接口的功能(如果已实现)。TestFS
不再跟随符号链接,以避免无限递归。
unicode
新的 CategoryAliases
映射提供类别别名名称的访问(如 “Letter” 对应 “L”)。
新的类别 Cn
和 LC
分别定义未分配的代码点和大小写字母。这些在 Unicode 中一直有定义,但在早期 Go 版本中被不慎遗漏。C
类别现在包含 Cn
,这意味着它已添加所有未分配的代码点。
unique
unique
包现在更积极、更高效且并行地回收 interned 值。因此,使用 Make
的应用程序在 intern 大量真正唯一的值时,不太可能出现内存膨胀。
以前,传递给 Make
且包含 Handle
的值需要多个垃圾收集周期才能回收(与 Handle
值链的深度成正比)。现在,一旦不再使用,它们会在单个周期内被及时回收。
端口
Darwin
如 Go 1.24 发布说明中所宣布,Go 1.25 需要 macOS 12 Monterey 或更高版本。已停止支持旧版本。
Windows
Go 1.25 是包含有问题的 32 位 windows/arm 端口(GOOS=windows
GOARCH=arm
)的最后一个版本。它将在 Go 1.26 中移除。
Loong64
linux/loong64 端口现在支持竞态检测器、使用 runtime.SetCgoTraceback
从 C 代码收集回溯信息,以及使用内部链接模式链接 cgo 程序。
RISC-V
linux/riscv64 端口现在支持 plugin
构建模式。
环境变量 GORISCV64
现在接受新值 rva23u64
,用于选择 RVA23U64 用户模式应用程序配置文件。