我们都知道,Go有一个很重要的特点,那就是它的编译速度非常快,编译速度是Go语言设计的时候就重点考虑的问题. 但是您有没有观察过Go语言编译后的二进制可执行文件的大小?我们先用一个简单的http server 的例子来看看。
This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on Medium. Thank you very much.
|
|
编译后的体积达到了6.5M
|
|
Go语言的编译器会对二进制文件的大小进行裁剪,如果您对这部分的内容感兴趣,请阅读我的另外一篇文章How Does the Go Compiler Reduce Binary File Size?
现在我们来尝试优化一下server
的大小。
消除调试信息
Go 编译器默认编译出来的程序会带有符号表和调试信息,一般来说 release 版本可以去除调试信息以减小二进制体积。
|
|
- -s:忽略符号表和调试信息。
- -w:忽略DWARFv3调试信息,使用该选项后将无法使用gdb进行调试。
体积从 6.5M 下降到 4.5M,下降约 30%。这是很好的第一步。
使用 upx
UPX is an advanced executable file compressor. UPX will typically reduce the file size of programs and DLLs by around 50%-70%, thus reducing disk space, network load times, download times and other distribution and storage costs.
在Mac 上可以通过brew 安装upx
|
|
单独使用upx 压缩
upx 有很多参数,最重要的则是压缩率,1-9
,1
代表最低压缩率,9
代表最高压缩率。
接下来,我们看一下,如果只使用 upx 压缩,二进制的体积可以减小多少呢。
|
|
压缩比例达到了 60%
upx + 编译器选项
同时开启 upx + -ldflags="-s -w"
|
|
最终我们得到的的可执行文件的大小是 1.4M 对比不开启任何压缩的6.5M,大约节约了80%的空间,对于大型应用,还是挺可观的。
upx 的原理
upx 压缩后的程序和压缩前的程序一样,无需解压仍然能够正常地运行,这种压缩方法称之为带壳压缩,压缩包含两个部分:
- 在程序开头或其他合适的地方插入解压代码;
- 将程序的其他部分压缩。
执行时,也包含两个部分:
- 首先执行的是程序开头的插入的解压代码,将原来的程序在内存中解压出来;
- 再执行解压后的程序。
也就是说,upx 在程序执行时,会有额外的解压动作,不过这个耗时几乎可以忽略。
如果对编译后的体积没什么要求的情况下,可以不使用 upx 来压缩。一般在服务器端独立运行的后台服务,无需压缩体积。
最后
https://stackoverflow.com/questions/3861634/how-to-reduce-go-compiled-file-size
这帖子里面有很多有意思的答案,
- 比如用c语言跟go语言实现相同的功能(小demo)c语言生成的可执行大小是 go 语言的1/20(为什么呢?)
- 在Go语言中我们使用
println
来替代fmt.println
就能避免引入fmt包,进一步缩小体积。