为什么要缩减Golang编译后的文件大小呢?不缩减可不可以呢。正常来说一般服务器硬盘资源相对来说都比较充足,但如果类似树莓派上的一些设备上,硬盘资源相对来说就不是那么充足,这时就需要我们斤斤计较文件大小了。首先,我们先对比一下两段Hello World代码

package main

import "fmt"

func main(){
 fmt.Println("hello world")
}


#include<stdio.h>

int main(){
    printf("Hello world!");
}

这两段代码并没有什么逻辑,仅仅是打印输入hello world,我们对这两个文件进行编译,查看编译后的文件大小。

admindeMacBook-Pro:$ go build -o main-go main.go
admindeMacBook-Pro:$ gcc main.c -o main-c
admindeMacBook-Pro:$ ls -lh
total 4312
-rwxr-xr-x  1 admin  staff    48K Nov 25 15:04 main-c
-rwxr-xr-x  1 admin  staff   2.0M Nov 25 15:04 main-go
-rw-r--r--  1 admin  staff    60B Nov 25 15:04 main.c
-rw-r--r--  1 admin  staff    71B Nov 25 14:59 main.go

看到了什么,两者编译后的大小竟然相差了43倍。仅仅只是输出Hello World,为什么Golang文件编译后的大小足足有2M呢?因为Golang程序它会静态链接某些运行时的库,而C程序则不是这种情况。那么如何缩减Golang程序大小呢,有以下三种方法

一、基于GccGo进行编译

什么是GccGo呢?GccGo是gcc专门用来编译Golang语言的。我们平常用go build来编译Golang语言的是GC,全称Golang Compiler,是Go语言官方编译器,也是自带的。两者有什么区别呢?

  • GccGo可以生成一个二进制文件,该二进制文件可以动态链接到libgo,这会使输出变小,但意味着要在目标计算机上安装相关的库。没有cgo的二进制文件没有此要求。
  • GC是Go语言原生的编译器,不需要安装,使用方便;而GccGo需要自已安装。
  • GC只支持一些主流的处理器,如x86、amd、ARM等。而GccGo支持基本上所有的处理器。
  • GC编译速度比GccGo快,而且Gccgo并不能支持编译所有的Golang版本,这个在使用时要注意。
  • GccGo能生成很好的执行代码,但缺少逃逸检测,会在很多小内存的分配和回收上损失一些性能。GC实现的不严谨,对32位系统支持很差。

gccgo需要提前下载安装,下载安装方式参考链接:https://golang.org/doc/install/gccgo

下面比较一下GccGo编译后的文件大小

admindeMacBook-Pro:$ gccgo -g main.go -o main-gccgo
admindeMacBook-Pro:$ ls -lh
-rwxr-xr-x  1 admin  staff    48K 11 25 15:04 main-c
-rw-r--r--  1 admin  staff    83K 11 25 16:02 main-gccgo
-rwxr-xr-x  1 admin  staff   2.0M 11 25 15:04 main-go
-rw-r--r--  1 admin  staff    60B 11 25 15:04 main.c
-rw-r--r--  1 admin  staff    71B 11 25 14:59 main.go

文件的大小虽然比C语言编译后的大了一倍,但相比GC编译已经缩小了20余倍,效果非常明显。

二、指定编译参数

第一种方式虽然文件大小减少的非常明显,但需要自己安装GccGo,而且GccGo并不支持所有的Golang版本,可能对我们并不是最好的选择,我们可以通过指定编译参数的方式减小,-s 的作用是去掉符号信息。 -w 的作用是去掉调试信息。

admindeMacBook-Pro:$ go build -ldflags "-s -w" -o main-ldflags main.go 
admindeMacBook-Pro:GoTest admin$ ls -lh
-rwxr-xr-x  1 admin  staff    48K Nov 25 15:04 main-c
-rw-r--r--  1 admin  staff     0B Nov 25 16:02 main-gccgo
-rwxr-xr-x  1 admin  staff   2.0M Nov 25 15:04 main-go
-rwxr-xr-x  1 admin  staff   1.5M Nov 25 16:15 main-ldflags
-rw-r--r--  1 admin  staff    60B Nov 25 15:04 main.c
-rw-r--r--  1 admin  staff    71B Nov 25 14:59 main.go

通过编译制定参数,文件虽然缩小,但是缩小的并不明显,由原来的2M大小,缩减到1.5M大小

三、UPX 压缩

UPX (the Ultimate Packer for eXecutables)是一款先进的可执行程序文件压缩器,压缩过的可执行文件体积缩小50%-70% ,这样减少了磁盘占用空间、网络上传下载的时间和其它分布以及存储费用。 通过 UPX 压缩过的程序和程序库完全没有功能损失和压缩之前一样可正常地运行,对于支持的大多数格式没有运行时间或内存的不利后果。 UPX 支持许多不同的可执行文件格式 包含 Windows 95/98/ME/NT/2000/XP/CE 程序和动态链接库、DOS 程序、 Linux 可执行文件和核心。

通过各系统的包管理工具一般可以自动安装 UPX。 例如 Centos 上 epel 库 yum install -y upx。 macos 上通过 brew 安装brew install upx

-o 指定压缩后的文件名。-9指定压缩级别,1-9。

admindeMacBook-Pro:$ brew install upx
admindeMacBook-Pro:$ upx -9 -o main-upx main-ldflags
admindeMacBook-Pro:$ ls -lh
-rwxr-xr-x  1 admin  staff    48K 11 25 15:04 main-c
-rw-r--r--  1 admin  staff     0B 11 25 16:02 main-gccgo
-rwxr-xr-x  1 admin  staff   2.0M 11 25 15:04 main-go
-rwxr-xr-x  1 admin  staff   1.5M 11 25 16:15 main-ldflags
-rwxr-xr-x  1 admin  staff   620K 11 25 16:15 main-upx
-rw-r--r--  1 admin  staff    60B 11 25 15:04 main.c
-rw-r--r--  1 admin  staff    71B 11 25 14:59 main.go

基于通过方式二的可执行文件进行再次进行压缩,文件大小已经由原来的1.5M变为现在的620K,一般可以满足正常需求了~

以上介绍了三种方式减少Golang程序编译后的体积,可根据自己的项目灵活选择,也可以多种方式结合着使用。

转自:https://zhuanlan.zhihu.com/p/313053187