Go 1.15

新的Go版本按时在今天发布了,本次发布没有重大的修改,Release Note:Go 1.15 Release Notes

值得关注的一些亮点如下:

  • 链接器优化
  • 改进了多核心环境下的小对象分配
  • X.509 CommonName废弃
  • GOPROXY自动跳过返回错误的代理
  • 新的嵌入式tzdata包
  • 多项核心库改进

操作系统与架构

Darwin

Go 1.15要求macOS 10.12 Sierra或更高的版本,不再支持以前的版本。

Go 1.15移除了对macOS、iOS、iPadOS、watchOS和tvOS(darwin/386和darwin/arm)上的32位二进制文件的支持。Go继续支持64位darwin/amd64和darwin/arm64。

Windows

现在使用-buildmode=pie的cmd/link标志时,会生成Windows ASLR可执行文件,Go 1.15在Windows上默认使用-buildmode=pie。

-race和-msan默认启用-d=checkptr,用于检查unsafe.Pointer的使用。

内置的DLL在收到信号时不再导致进程退出(例如终端上的Ctrl-C)。

Android

链接二进制文件时,Go 1.15会选择最新版本NDK中可用的lld链接器,该链接器可避免某些设备的崩溃,在未来的NDK版本中会成为默认链接器。

OpenBSD

在GOARCH=arm和GOARCH=arm64中增加了对OpenBSD 6.7的支持。

RISC-V

GOOS=linux GOARCH=riscv64版本的开发有了一定进展,改善了稳定性和性能,现在也支持异步抢占了。

386

Go 1.15是最后一个支持仅x87浮点硬件(GO386=387)的版本,未来版本至少需要SSE2的支持,GOARCH=386的要求最低将提升为Intel Pentium 4(2000发布)或 AMD Opteron/Athlon 64(2003发布)。

工具

Go命令

GOPROXY环境变量现在支持跳过返回错误的代理。代理URL现在可以用逗号或竖线字符分隔。

如果代理URL后面带有逗号,则该go命令将仅在404或410 HTTP响应后尝试列表中的下一个代理。如果代理URL后面带有竖线字符,则该go命令将在出现任何错误后尝试列表中的下一个代理。默认的GOPROXY(https://proxy.golang.org,direct)在发生错误的情况下不会回退。

go test

现在更改-timeout标志会使缓存的测试结果失效。如果在短时间内重新调用go test,则超时的缓存结果不再视为通过。

标识位解析

go test和go vet中的各种标志解析问题已经修复。值得注意的是,GOFLAGS中指定的标志得到了更一致的处理,-outputdir标志现在使用go命令的工作目录转译相对路径,而不是每个测试的工作目录。

模块缓存

现在可以使用GOMODCACHE环境变量设置模块缓存的位置。GOMODCACHE的默认值为GOPATH [0]/pkg/mod,这是之前的模块缓存的位置。

Vet

string(x)告警

现在,当x为整形而不是rune或byte时,vet工具会警告有关string(x)形式的转换。Go的经验表明,许多这种形式的转换错误地假定string(x)的结果为整数x的字符串表示形式。实际上,它求值为包含x值的UTF-8编码的字符串。例如,string(9786)的求值结果不是字符串"9786”,计算结果为字符串”\xe2\x98\xba"或"☺”。

使用go test时,默认情况下会启用这个新的vet检查。

我们正在考虑在以后的Go版本中禁止这种转换。也就是说,当整形x的类型rune或byte时,才允许执行string(x)转换。这样的语言更改无法向后兼容。这个vet检查将作为尝试更改语言的第一步。

无法进行接口转换的警告

现在,当一种接口类型转换到另一种接口类型始终失败时,vet工具会产生无法进行接口转换的警告。如果两种接口类型都实现了具有相同名称但具有不同类型签名的方法,就会发生这种情况。

使用go test时,默认情况下会启用这个新的vet检查。

我们正在考虑在Go的未来版本中禁止无法执行的接口类型转换。这样的语言更改无法向后兼容。这个vet检查将作为尝试更改语言的第一步。

运行时

如果使用来自以下任意类型的值:bool,complex64,complex128,float32,float64,int,int8,int16,int32,int64,字符串,uint,uint8,uint16,uint32,uint64,uintptr,来调用panic,则其地址和数值将被打印。以前,仅对于这些类型的值才适用(例如,打印int类型而不打印通过type自定义的int类型)。

在Unix系统上,如果使用kill命令或kill系统调用向Go程序发送SIGSEGV,SIGBUS或SIGFPE信号,且该信号未被os/signal.Notify处理时,则通知Go程序携带stack tarce可靠地崩溃。在早期版本中,该行为是无法预测的。

现在小对象的分配在高内核数下表现更好,即使是最坏情况下,延迟也更低了。

将小整数值转换为接口值不再触发内存分配。

现在,已关闭通道上的非阻塞接收与打开通道上的非阻塞接收表现一致。

编译器

unsafe包的安全规则允许在调用某些函数时将unsafe.Pointer转换为uintptr。以前在某些情况下,编译器允许进行多次链接转换(例如syscall.Syscall(…, uintptr(uintptr(ptr)), …))。编译器现在只需要一次转换。使用多次转换的代码应进行更新以满足安全规则。

通过消除某些类型的GC元数据和未使用的类型元数据,Go 1.15与Go 1.14相比,将典型的二进制文件大小减少了大约5%。

工具链现在通过将函数与32字节边界对齐并填充跳转指令来缓解GOARCH=amd64上的Intel CPU erratum SKX102。虽然这会增加二进制文件大小,但上述的二进制大小改进远超过它。

Go 1.15在编译器和汇编器中都添加了-spectre标志,以允许启用Spectre缓解措施。这主要是作为“深度防御”机制提供的,几乎是永远不需要的。有关详细信息,请参见Spectre Wiki页面。

现在,编译器将拒绝 //go: 编译器指令,这些指令对于它们应用的声明没有任何意义,并出现"misplaced compiler directive"错误。此类错误使用的指令在之前已经存在问题,但编译器隐式忽略了它们。

现在,编译器的-json优化日志记录报告大副本(> = 128字节),并包含转义分析决策的说明。

链接器

此版本包括对Go链接器的重大改进,可减少链接器资源的使用(时间和内存)并提高代码的健壮性和可维护性。

对于在amd64架构上运行的基于ELF的操作系统(Linux,FreeBSD,NetBSD,OpenBSD,Dragonfly和Solaris),代表性的大型Go程序集的链接速度提高20%,平均所需内存减少30%。其他架构/OS组合也有些许改进。

改进链接程序性能的关键因素是新设计的目标文件格式,以及内部阶段的改进以提高并发性(例如,对符号并行应用重定位)。 Go 1.15中的目标文件会比Go 1.14文件稍大。

这些更改是Go链接器现代化多版本项目的一部分,这意味着将来的版本中有望对链接器进行其他改进。

现在,链接器在linux/amd64和linux/arm64上默认使用-buildmode=pie的内部链接模式,因此这些配置不再需要C链接器了。但仍然可以使用-ldflags=-linkmode=external标志来使用外部链接模式(这是Go 1.14中-buildmode=pie的默认设置)。

Objdump

objdump工具现在支持使用-gnu标志以GNU汇编器语法进行反汇编。

核心库

新的嵌入式tzdata包

Go 1.15包含了一个新程序包,time/tzdata。它允许将时区数据库嵌入程序中。导入该软件包后,在本地系统缺少时区数据库时,仍可获取到时区信息。您还可以在构建时添加-tags timetzdata来嵌入它。两种方法都会使程序的大小增加大约800 KB。

Cgo

Go 1.15会将C类型EGLConfig转换为Go类型uintptr。此更改类似于Go 1.12和更高版本EGLDisplay,Darwin的CoreFoundation和Java的JNI类型的处理方式。有关更多信息,请参见cgo文档

X.509 CommonName废弃

未提供Subject Alternative Names时,使用X.509证书上的CommonName作为host名的方式已默认禁用。可以通过在GODEBUG环境变量中配置x509ignoreCN=0来临时启用。

请注意,如果CommonName主机名无效,则无论GODEBUG是否设置了x509ignoreCN,它都将被忽略。

其他轻微修改

小修小改:Minor changes to the library