Go 1.25 重磅发布:性能飞跃、工具升级与新一代 GC 来袭

前言

Gopher 们,Go 1.25.0 发布啦!Go 1.25.0 相比 Go 1.24.0 在工具链、运行时、编译器、链接器以及标准库方面都有改进,并新增了一个标准库包。此外,还包含了针对特定移植平台的更改,以及对 GODEBUG 设置的更新。让我们一起来看看 Go 1.25.0 带来了哪些新变化吧!

准备好了吗?准备一杯你最喜欢的咖啡或茶,随着本文一探究竟吧。

快速安装

您可以从下载页面下载二进制和源代码发行版:

Go 1.25.0 下载

如果你已经安装了其他的 Go 语言版本,你也可以通过以下命令快速安装 Go 1.25.0 版本:

bash 复制代码
$ go install golang.org/dl/go1.25.0@latest
$ go1.25.0 download
Downloaded   0.0% (   xxx / xxxxx bytes) ...
Downloaded  50.4% (   xxx / xxxxx bytes) ...
Downloaded 100.0% (   xxx / xxxxx bytes)
Unpacking /Users/chenmingyong/sdk/go1.25.0/go1.25.0.darwin-arm64.tar.gz ...
Success. You may now run 'go1.25.0'

$ go1.25.0 version
go version go1.25.0 darwin/arm64

语言层面的变更

Go 1.25 在语言层面没有任何变更。不过,在语言规范中,核心类型 的概念已被删除,以支持更专用的语法。

工具链层面的变更

Go command 命令

  • go build -asan

    现在默认会在程序退出时执行内存泄漏检测。如果由 C 分配的内存既没有被释放,也没有被 CGo 分配的其他内存引用,就会报告错误。 如果你想禁用这些新的错误报告,可以在运行程序时通过设置环境变量:ASAN_OPTIONS=detect_leaks=0 来关闭泄漏检测。

  • 减少预构建工具二进制文件

    Go 1.25 版本将包含更少的预构建工具二进制文件。编译器、链接器等核心工具链二进制文件仍会提供,但不在构建或测试操作中直接调用的工具,将由 go tool 在需要时构建并运行。

  • go.mod 新增 ignore 指令

    该命令可用于指定 go 命令应忽略的目录。匹配包模式(如 all./...)时,这些目录及其子目录中的文件将被忽略,但它们仍会被包含在模块 zip 文件中。

  • go doc -http

    go doc 命令新增 -http 选项,可启动一个文档服务器,展示所请求对象的文档,并在浏览器窗口中打开。

  • go version -m -json

    go version 命令新增 -m -json 选项,可打印给定 Go 二进制文件中嵌入的 runtime/debug.BuildInfo 结构的 JSON 编码。

  • 模块路径支持仓库子目录

    go 命令现在支持将仓库的子目录作为模块根路径解析,使用以下 go-import 元信息语法:

    html 复制代码
    <meta name="go-import" content="root-path vcs repo-url subdir">

    其中 root-path 对应于 repo-url 下的 subdir,并由版本控制系统 vcs 管理。

  • 新的 work 包模式

    匹配工作模块(以前称为 main 模块)中的所有包:

    • 在模块模式下,是单一的工作模块
    • 在工作区模式下,是一组工作区模块
  • 更新 go 版本号时的行为调整

    go 命令更新 go.modgo.work 文件中的 go 行时,将不再添加 toolchain 行来指定当前命令的版本。

Vet 命令

go vet 新增了两个分析器:

  • waitgroup

    检测错误放置的 sync.WaitGroup.Add 调用。

  • hostport

    检测使用fmt.Sprintf("%s:%d", host, port) 构造传给 net.Dial 的地址的情况,因为这种方式不支持 IPv6。分析器会建议改用 net.JoinHostPort

Runtime 层面的变更

容器感知的 GOMAXPROCS

GOMAXPROCS 的默认行为已发生变化。

在早期版本中,GOMAXPROCS 默认值为程序启动时可用的逻辑 CPU 数量(runtime.NumCPU)。 Go 1.25 引入了两项新变化:

  1. Linux 平台 如果进程所在的 cgroup 存在 CPU 带宽限制,运行时会考虑该限制。 如果该限制低于可用逻辑 CPU 数量,则 GOMAXPROCS 会默认取较小的值。 在如 Kubernetes 等容器运行时系统中,cgroup CPU 带宽限制通常对应 CPU limit 配置选项。Go 运行时不会考虑 CPU requests 配置。

  2. 所有操作系统

    如果可用逻辑 CPU 数量或 cgroup CPU 带宽限制发生变化,运行时会定期更新 GOMAXPROCS

以上两种行为在以下情况下会自动禁用:

  • 通过 GOMAXPROCS 环境变量手动设置
  • 或调用 runtime.GOMAXPROCS 手动设置

此外,也可以通过 GODEBUG 设置显式关闭:

  • containermaxprocs=0 ------ 禁用容器 CPU 限制感知
  • updatemaxprocs=0 ------ 禁用动态更新

为了支持读取最新的 cgroup 限制,运行时会在整个进程生命周期内缓存相关 cgroup 文件的文件描述符。

新的实验性垃圾收集器

Go 1.25 引入了一个新的实验性垃圾收集器,其设计提升了标记和扫描小对象时的性能,改善了数据局部性和 CPU 可扩展性。

基准测试结果有所差异,但在大量依赖垃圾回收的真实程序中,预期可减少 10%--40%GC 开销。

启用方法:

bash 复制代码
GOEXPERIMENT=greenteagc

在构建时设置该环境变量即可开启。

该设计仍在持续演进中,官方鼓励 Go 开发者尝试使用并反馈体验感受。

Trace Flight Recorder

运行时执行追踪(execution trace)一直是分析和调试应用底层行为的强大手段,但由于文件体积大、持续写入成本高,一直不适合用来调试罕见事件。

新的 runtime/trace.FlightRecorder API 提供了一种轻量化方案:

  • 持续将追踪数据写入内存中的环形缓冲区
  • 当发生重要事件时,程序可调用 FlightRecorder.WriteTo 将最近几秒的追踪数据快照写入文件
  • 仅捕获关键时刻的追踪,生成的文件体积显著减小

可通过 FlightRecorderConfig 配置捕获的时间长度和数据量。


未处理 panic 输出变更

当程序因未处理的 panic 退出(panicrecover 后又重新抛出)时,输出信息不再重复打印 panic 值的文本。

旧行为示例

text 复制代码
panic: PANIC [recovered]
	panic: PANIC

新行为示例

text 复制代码
panic: PANIC [recovered, repanicked]

Linux 下的 VMA 命名

在支持匿名虚拟内存区域(VMA)命名的 Linux 内核(CONFIG_ANON_VMA_NAME)中,Go 运行时会为匿名内存映射添加用途标注,例如:

csharp 复制代码
[anon: Go: heap]

用于堆内存的映射。

可通过 GODEBUG 设置禁用:

ini 复制代码
decoratemappings=0

编译器(Compiler)层面的变更

nil 指针检查修复

本次版本修复了一个在 Go 1.21 引入的编译器 Bug,该 Bug 可能会错误地延迟 nil 指针检查。

例如,以下程序在之前版本中(错误地)能够正常运行,现在会(正确地)触发 nil 指针异常:

go 复制代码
package main

import "os"

func main() {
    f, err := os.Open("nonExistentFile")
    name := f.Name()
    if err != nil {
        return
    }
    println(name)
}

这个程序是不正确的,因为它在检查错误之前就使用了 os.Open 的返回结果。

如果 err 不为 nil,则 f 可能为 nil,此时调用 f.Name() 应当触发 panic

然而在 Go 1.21~1.24 中,编译器会将 nil 检查延迟到错误检查之后,导致程序错误地运行成功,违反了 Go 语言规范。

Go 1.25 中,此问题已修复,程序会在预期位置触发 panic

DWARF5 支持

Go 1.25 的编译器和链接器现在会生成符合 DWARF v5 的调试信息。 新版本的 DWARF 格式可以减少 Go 二进制文件中调试信息占用的空间,并加快链接速度,尤其是大型 Go 二进制文件。

可通过以下方式禁用 DWARF 5(可能在未来版本移除该回退选项):

bash 复制代码
GOEXPERIMENT=nodwarf5

在构建时设置此环境变量即可。

更快的切片(Slices)

编译器现在在更多情况下可以将切片的底层存储分配在栈上,从而提升性能。 不过,这一变化也可能放大错误使用 unsafe.Pointer 的风险(参见 issue 73199)。

为了定位相关问题,可以使用 bisect 工具并加上以下编译标志:

bash 复制代码
-compile=variablemake

用来查找导致问题的具体分配位置。

此外,也可以通过以下方式关闭所有新的切片栈分配:

bash 复制代码
-gcflags=all=-d=variablemakehash=n

链接器(Linker)

链接器现在支持新的命令行选项:

bash 复制代码
-funcalign=N

用于指定函数入口的对齐方式。默认值依赖于平台,本次版本中默认值未作更改。

标准库层面的变更

新增与重大变更

testing/synctest(并发测试支持)

  • 用于测试并发代码的新包。
  • Test 函数 :在隔离的 bubble 中运行测试,time 包会用虚拟时钟,所有 goroutine 阻塞时时间瞬间前进。
  • Wait 函数 :等待当前 bubble 内所有 goroutine 阻塞。
  • 最早在 Go 1.24GOEXPERIMENT=synctest 试验性发布,现在正式可用。
  • API 兼容到 Go 1.26

encoding/json/v2(实验性 JSON 实现)

  • 需要设置 GOEXPERIMENT=jsonv2 启用。

  • 两个新包:

    • encoding/json/v2:现有 encoding/json 的重大修订版。
    • encoding/json/jsontext:底层 JSON 语法处理。
  • 启用后,encoding/json 会使用新实现(行为基本一致,但错误信息可能不同)。

  • 提供更多选项,解码速度显著提升,编码性能持平。

对标准库的细微改动

以下列出了主要变更,完整内容请参见 Go 1.25 版本说明文档。

go/parser

  • ParseDir 已弃用。

go/token

  • 新增 FileSet.AddExistingFiles 方法,可将已有文件加入 FileSet,方便长生命周期应用管理多个 FileSet

go/types

  • Var.Kind:分类变量类型(包级、接收器、参数、返回值、本地变量、结构体字段)。
  • LookupSelection:按类型查找字段/方法,返回 Selection 结果。

hash

  • 新接口 XOF(可扩展输出函数,如 SHAKE)。
  • 新接口 Cloner :标准库 Hash 都实现了,可克隆当前状态。

hash/maphash

  • 新增 Hash.Clone(实现 hash.Cloner)。

io/fs

  • 新增 ReadLinkFS 接口(读符号链接)。

log/slog

  • GroupAttrs:用切片创建分组属性。
  • Record.Source():返回源码位置。

net

  • LookupMX / Resolver.LookupMX:现在可返回看似 IP 地址的 DNS 名。

  • Windows

    • ListenMulticastUDP 支持 IPv6
    • 支持在 os.File 与网络连接之间转换(FileConnFilePacketConnFileListener 等)。

net/http

  • 新增 CrossOriginProtection:基于 Fetch Metadata 防御 CSRF,不依赖 token/cookie,可配置白名单。

os

  • WindowsNewFile 支持异步 I/O 句柄(结合 Go runtime IOCP,非阻塞并支持 deadline)。
  • DirFSRoot.FS 实现 ReadLinkFS
  • CopyFS 支持符号链接。
  • Root 新增多种文件操作方法(ChmodChownRenameSymlink 等)。

reflect

  • 新增 TypeAssert:直接从 Value 转换为目标类型,避免额外分配。

sync

  • 新增 WaitGroup.Go:简化启动 goroutine 并计数的常用模式。

testing

  • T.Attr / B.Attr / F.Attr:向测试日志输出属性。
  • Output:返回写入测试输出流的 io.Writer
  • AllocsPerRun:在并行测试时会 panic(避免结果不稳定)。

testing/fstest

  • MapFS 实现 ReadLinkFS
  • TestFS 测试 ReadLinkFS,并不再跟随符号链接。

unicode

  • 新增 CategoryAliases 映射(别名如 LetterL)。
  • 新增 Cn(未分配码点)与 LC(大小写字母)类别。

unique

  • Make 回收 interned 值更积极、更高效、并行化,减少内存膨胀风险。

移植(Ports)层面的变更

Darwin

Go 1.24 发布说明中所述,Go 1.25 要求 macOS 12 Monterey 或更高版本。 对更早版本的支持已停止。

Windows

Go 1.25 是最后一个包含有缺陷的 32windows/arm 移植版本(GOOS=windows GOARCH=arm)的发行版。 该移植版本将在 Go 1.26 中移除。

Loong64

linux/loong64 移植版本现在支持:

  • 数据竞争检测器(race detector)
  • 通过 runtime.SetCgoTraceback 从 C 代码收集回溯信息
  • 使用 internal 链接模式构建 cgo 程序

RISC-V

linux/riscv64 移植版本现在支持 plugin 构建模式。

此外,环境变量 GORISCV64 现在接受一个新的取值 rva23u64,用于选择 RVA23U64 用户模式应用配置文件(user-mode application profile)。

小结

Go 1.25 在工具链、运行时、编译器、链接器以及多平台支持方面都有显著改进,并引入了实验性功能(如新垃圾收集器与 Trace Flight Recorder)供开发者提前试用。

此次更新不仅提升了性能与调试体验,也修复了长期存在的编译器 Bug,并调整了部分默认行为以更好适配现代运行环境。

无论是日常开发、性能调优还是平台适配,Go 1.25 都为未来版本奠定了更稳固的基础。

后续,我将深入介绍每个重要更新的具体内容,关注我,更多精彩的更新分析,敬请期待!


你好,我是陈明勇,一名热爱技术、乐于分享的开发者,同时也是开源爱好者。

我专注于分享 Go 语言相关的技术知识,同时也会深入探讨 AI 领域的前沿技术。

成功的路上并不拥挤,有没有兴趣结个伴?

Go 开源库代表作go-mongoxgo-optioner

相关推荐
风象南7 分钟前
SpringBoot 实现在线查看内存对象拓扑图 —— 给 JVM 装上“透视眼”
后端
用户40993225021214 分钟前
定时任务系统如何让你的Web应用自动完成那些烦人的重复工作?
后端·github·trae
Lx35214 分钟前
MapReduce性能调优:从理论到实践的经验总结
大数据·hadoop·后端
bobz96530 分钟前
小而精的 HRM 模型
后端
crossoverJie1 小时前
在多语言的分布式系统中如何传递 Trace 信息
分布式·后端·开源
用户848508146901 小时前
SurrealDB 快速上手教程
数据库·后端
用户6147493427741 小时前
JeecgBoot 项目理解与使用心得
后端
郭京京2 小时前
go常用包json
go
ZIQ2 小时前
单机线程池任务防丢设计与实现思路
后端