Golang 1.15展望,推出全新链接器,可执行包更小,性能更高

Golang语言第15个主要版本1.15预计会于今年8月1日发布。由于疫情影响该版本的变化将会比正常版本变化小一点。主要着重点在顶层和配套上,将会推出一个全新的链接器。新链接器将能加速构建效率,并且能一定程度减小生成的二进制执行文件的大小。此外,Golang 1.5还在语言运行时性能,支撑体系结构,标准库等方面做改善。

概述

自从Golang1.0发布以来,Go团队一直在每个版本中对工具和标准库进行改进,但始终对语言的变化持保守态度。从1.0版本开始,团队的重点一直是稳定性和简单性。将Golang的向后兼容性承诺保证Golang 1.x编写的程序都将继续正常运行,保持不变Go。在1.x版本下程序能继续"正常运行",但更新的版本运行速度会更快。

在即将到来的Golang 1.15版本中,语言规范的变化基本很小。主要改进包括工具,编译器的性能以及标准库。

Golang 1.15在5月1日进入功能冻结状态,保持正常的第六个月,Go团队计划在8月1日发布最终版本。

Golang开发模型与大多数开源语言完全不同。该语言是由谷歌设计的,大多数核心开发人员都在谷歌工作。Golang语言执行BSD风格的许可,其开发是公开进行的,并在golang-dev邮件列表进行一般性讨论。在GitHub仓库问题中提出并讨论更改或新功能,并通过对Gerrit对代码变化进行审阅。

全新的链接器

Golang 1.15中最大的变化是完全重写的链接器。新的连接器是核心开发者Austin.Clements 2019年9月设计并开始开发的。新连接器将带来三方面的改善:

并行编译:可以并行化,编译开始支持CPU并行完成的,但是链接步骤中必须在构建结束时以串行方式完成。此外,Go工具会缓存编译器的结果。

避免使用字符串来改进关键数据结构。当前的链接器使用按字符串索引的大符号表。新设计通过使用符号编号技术来尽可能避免使用字符串。

避免一次将所有输入目标文件加载到内存中。新的链接程序的内存占用更好,可以通过较少的内存来处理大型程序。(当前的链接程序将其20%以上的时间花费在GC上)。

由于初始链接器的作者Ken.Thompson大大已经退休,启用全新的编译器也可以增加程序可维护性。考虑到长期的广泛变化,这项工作是在仅在稳定点合并到master的分支(dev.link)上完成的。与1.14版本相比,可以使构建更快并且使用的内存更少,但是某些功能(例如,使用DWARF 5调试格式)将必须要等下一个版本1.16。

较小的二进制文件

相关的一些改进可以减少使用Golang 1.15可执行文件的大小。根据开发者一个测试,新的链接器删除了很多未使用的代码,从而使程序可执行文件大小从Golang 1.14中的8.2MB降低到1.15中的3.9MB。对于更实际的程序,生成的二进制执行文件大小最大可以减少22%。

执行程序大小改善主要得益于新链接程序对中未使用的代码消除以及一些针对性的改进,比如CL 230544,减少了可执行文件中包含的堆栈和寄存器映射的数量。Golang的垃圾回收器(GC)使用这些映射来确定哪些对象仍然存在,但现在仅在调用时才需要,而不是每个指令都需要。通过该改进Golang二进制文件的大小减少了5.7%;它还大大加快了编译和链接的速度。

由于Go能够在运行时检查类型,因此Golang二进制文件包含大量的类型信息。将符号的类型信息转换为接口,则仅将其类型信息包含在输出中。CL 231397更改将一个典型的hello-world程序大小减少7.2%。

二进制大小还有其他一些小改进,例如CL 228111,如果只使用TLS客户端和服务器代码,则避免在输出中同时包含TLS客户端和服务器代码,从而减少TLS拨号hello world程序大小减少3.2%。

性能提升

Go 1.15引入了许多次要的性能改进,但是其中两个值得注意的改进来自多产的非Google贡献者Josh Bleecher Snyder。当将小整数转换为接口值时,CL 216401避免分配内存,从而使编译时的汇编时间缩短2%。转换为接口值就像其他语言中的"装箱"一样。该优化在本质上类似于Python的小型整数缓存,尽管由于静态类型的缘故,它在Go中的发生频率要低得多。

Snyder的第二个更改是编译器和运行时内部的CL 226367,它使编译器可以将更多的x86寄存器用于垃圾收集器的写屏障调用。当GC与用户代码并发运行时,Go使用写屏障(有点像锁)来维护堆上的数据完整性。这样可以减少二进制文件的数量,并使编译时间缩短1%。

通过重新设计内存分配器的mcentral数据结构以减少锁竞争,大大提高了大块内存分配的吞吐量。对于12KB或更大的块,新的代码快两倍以上。

工具和ports

Golang模块系统(Go的依赖管理系统)首先在Go 1.11中引入,并在1.13中添加了对模块镜像和代理的支持。1.15版增加了对错误回退代理的支持,如果下载模块源代码时第一个代理失败,go工具可以回退到备用代理。使用GOMODCACHE环境变量的新"|"分隔符指定备用代理机。

Go 1.15删除了两个较旧的ports:darwin/86和darwin/arm,它们在macOS和其他Apple操作系统上提供了32位二进制文件。由于macOS Catalina不支持运行32位应用程序,因此删除这些端口将有助于释放macOS构建机器并略微缩小编译器。这些ports在Go 1.14版本中宣布已弃用,并将在Go 1.15中将默认删除。

另外,linux/arm64 port已升级为"一流port",所以linux/arm64版本如果不完成,将不能发布Golang 版本。Go团队提供了官方二进制文件和安装文档。Linux 64位Arm现在至少已经和32位Arm一样重要,后者已经是一流的port。

在Windows上,Go 1.15现在默认会生成使用地址空间布局随机化(ASLR)可执行文件。ASLR使用与位置无关的代码在启动时随机分配各个数据区域的地址,从而使攻击者更难以预测目标地址并创建内存破坏漏洞。

标准库添加

Go的标准库很大且相当稳定;在Go 1.15中,仅添加了相对较小的一些功能。

标准库的testing包非常简单,Go的哲学是避免使用特定于领域的语言来编写测试和断言,而只是编写开发人员已经知道的普通Go。但是核心开发人员发现创建一个临时目录非常有用,为此批准添加一个TempDir()方法,该方法自动在当前测试创建一个临时目录,并在测试完成后自动将其删除。

time/tzdata包添加到允许的可执行文件中嵌入的时区数据库的静态副本。由于它为可执行文件增加了约800K,可以通过导入time/tzdata包或通过使用timetzdata build标签进行编译。嵌入式数据库可以使时区数据库在某些系统(尤其是Windows)上的访问更加一致和可靠,并且在Docker容器和Go Playground等虚拟化环境中也很有用。

总结

Golang使用GitHub问题来跟踪所有错误和功能请求,因此可以在Go 1.15里程碑中查看已解决的问题列表,获取更详细的发版信息。

Golang 1.15最终版本将在在2个月后发布,目前可以使用gotip工具轻松地构建1.15测试环境测试。下个月 6月1日将会发布的beta版二进制包,可以到时候可以直接使用beta版本。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200513A0F6D600?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券