Go 1.7 让二进制文件变得更小

软件架构 Go语言   2016-09-02 16:38:10 发布
您的评价:
     
0.0
收藏     0收藏
文件夹
标签
(多个标签用逗号分隔)

引言

Go语言是为编写服务端软件而设计的,这也是为什么今天它被广泛使用的原因。因此大量的在运行时和编译器的优化工作都集中在与服务端软件相关的问题:延时、易于部署、精确的垃圾回收、启动快速以及性能。

因为Go大量使用于不同类型的程序,因此必须考虑一些新的问题。其中之一是二进制文件的大小。虽然这个问题已经被发现很久了(issue #6853在两年前被提出),但是随着人们越来越多的在小型设备(比如树莓派或者移动设备)上部署Go的二进制文件,意味着Go1.7的发布能收到更多的关注。

在Go 1.7中的工作

Go1.7中的三个重大的改变影响了二进制文件的大小。

第一个是在这个版本针对AMD64启用了新的SSA后端。虽然引入SSA的主要动机是为了改善性能,但是产生的代码体积也小了。SSA后端把Go的二进制文件体积压缩大约5%。我们期望在Go1.8版本发布时,ARM和MIPS这些RISC架构的后端换为SSA,能带来更大的收益。

第二个改变是函数裁剪。直到1.6版本,虽然有些方法从未被调用,但是在所有使用的类型的所有的方法都被保留了。这是因为他们可能通过接口被调用或者使用反射包被动态地调用。现在编译器丢弃了那些不匹配接口的所有未导出的方法。类似地,如果相应的反射特性没有在程序中被用到,链接器可以丢弃其他未导出方法,这些方法只有通过反射才能获取到。这个改变可以把二进制文件的体积压缩5-20%。

第三个改变是反射包使用的运行时类型信息采用了更加紧凑的格式。编码格式最初被设计为使得运行时和反射包的译码器尽可能地简单。通过使得这些代码稍微难以阅读,在不影响Go程序的运行时性能的前提下,我们压缩了格式。新的格式把Go二进制文件的体积进一步压缩了5-15%。为Android编译的动态库和为iOS归档文件进一步压缩,因为新的格式包含更少的指针,而这些指针在位置独立的代码处需要动态重映射。

另外,还有很多小改进,比如改良的接口数据布局,更好的静态数据布局以及简化的依赖。比如,HTTP client不再在整个HTTP server链接。改变的完整修改列表可以在issue #6953得到。

结果 当使用了Go 1.7,典型的程序(从小玩具到大型生产项目)的体积大约减小了30%。

规范的hello world程序的体积从2.3MB减小到1.6MB。

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

如果编译时没有调试信息,现在静态链接的二进制文件小于1MB。

测试这个特性,我采用了一个更大的生产环境程序,jujud,其体积从94MB减小为67MB。

地址无关 的二进制文件可以减小50%。 在 地址无关 的可执行程序(PIE)中,在只读数据段的指针需要动态重映射。因为新的类型信息格式通过段偏移单元代替了了指针,这样,每个指针节省了28个字节。

移除调试信息的 地址无关 的可执行程序对于移动开发者很重要,因为这是发布到手机端的程序。因为下载大体积的应用程序的用户体验差,所以体积减少对他们来说是个好消息。

未来的工作

一些运行时类型信息的改变没有赶上Go1.7版本冻结,但是希望会在1.8版本加入。这些会进一步减小程序体积,尤其是对 地址无关 的程序。

这些改变都是保守的,减小二进制文件的体积不会增加编译时间、启动时间、整体的运行时间以及内存使用量。我们会进行更彻底的做法来减小二进制文件的体积:upx工具可以把二进制文件的体积进一步压缩50%,代价是增加启动时间和潜在的内存使用量。针对非常小的系统(可能在钥匙挂上),我们会编译一个没有反射的Go,虽然还不确定这样一个有限制的语言是否是非常有用。在运行时中,当计算每个kb字节时,我们会使用稍微慢点但是更紧凑的算法。所有的这些需要在后续的开发周期中做更多的调研。

 

 

来自:http://mp.weixin.qq.com/s?__biz=MjM5OTcxMzE0MQ==&mid=2653369749&idx=1&sn=e52cd2766404f27bf47cb95ef22c00f0&scene=1&srcid=0822m02c3Uj65Sazdgw1FG4A&from=groupmessage&isappinstalled=0

 

扩展阅读

Go语言总结和学习指南
[译] Go 1.7 让二进制文件变得更小
Go语言开发工具,LiteIDE 开发工具指南
windows下用go语言写程序
Go语言随机测试工具go-fuzz

为您推荐

非常详细的 Docker 学习笔记
Java程序员快速入门 go 语言
Memcached与Redis
运维工程师常用到的Linux命令
[译] Go 1.7 让二进制文件变得更小

更多

软件架构
Go语言
Google Go/Golang开发