前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Go高性能编程EP2: 通过upx 缩小可执行二进制文件的体积

Go高性能编程EP2: 通过upx 缩小可执行二进制文件的体积

作者头像
用户11547645
发布2025-03-07 16:09:43
发布2025-03-07 16:09:43
8500
代码可运行
举报
文章被收录于专栏:萝卜要加油萝卜要加油
运行总次数:0
代码可运行

我们都知道,Go有一个很重要的特点,那就是它的编译速度非常快,编译速度是Go语言设计的时候就重点考虑[1]的问题. 但是您有没有观察过Go语言编译后的二进制可执行文件的大小?我们先用一个简单的http server 的例子来看看。

代码语言:javascript
代码运行次数:0
复制
import (  
"fmt"
"net/http"
    )  
funcmain() {  
// create a http server and create a handler hello, return hello world  
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {  
       fmt.Fprintf(w, "Hello, World\n")  
    })  
// listen to port 8080  
    err := http.ListenAndServe(":8080", nil)  
if err != nil {  
return
    }  
}
---

编译后的体积达到了6.5M

代码语言:javascript
代码运行次数:0
复制
➜  binary-size git:(main) ✗ go build  -o server main.go                 
➜  binary-size git:(main) ✗ ls -lh server 
-rwxr-xr-x  1 hxzhouh  staff   6.5M Jul  2 14:20 server

Go语言的编译器会对二进制文件的大小进行裁剪,如果您对这部分的内容感兴趣,请阅读我的另外一篇文章How Does the Go Compiler Reduce Binary File Size?[2]

现在我们来尝试优化一下server 的大小。

消除调试信息

Go 编译器默认编译出来的程序会带有符号表和调试信息,一般来说 release 版本可以去除调试信息以减小二进制体积。

代码语言:javascript
代码运行次数:0
复制
➜  binary-size git:(main) ✗ go build -ldflags="-s -w" -o server main.go
➜  binary-size git:(main) ✗ ls -lh server                              
-rwxr-xr-x  1 hxzhouh  staff   4.5M Jul  2 14:30 server
  • -s:忽略符号表和调试信息。
  • -w:忽略DWARFv3调试信息,使用该选项后将无法使用gdb进行调试。 体积从 6.5M 下降到 4.5M,下降约 30%。这是很好的第一步。

使用 upx

UPX[3] 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

代码语言:javascript
代码运行次数:0
复制
brew install upx

单独使用upx 压缩

upx 有很多参数,最重要的则是压缩率,1-91 代表最低压缩率,9 代表最高压缩率。 接下来,我们看一下,如果只使用 upx 压缩,二进制的体积可以减小多少呢。

代码语言:javascript
代码运行次数:0
复制
➜  binary-size git:(main) ✗ go build -o server main.go && upx -9 server && ls -lh server 
-rwxr-xr-x  1 hxzhouh  staff   3.9M Jul  2 14:38 server

压缩比例达到了 60%

upx + 编译器选项

同时开启 upx + -ldflags="-s -w"

代码语言:javascript
代码运行次数:0
复制
➜  binary-size git:(main) ✗ go build -ldflags="-s -w"  -o server main.go && upx --brute server && ls -lh server 
-rwxr-xr-x  1 hxzhouh  staff   1.4M Jul  2 14:40 server

最终我们得到的的可执行文件的大小是 1.4M 对比不开启任何压缩的6.5M,大约节约了80%的空间,对于大型应用,还是挺可观的。

upx 的原理

upx 压缩后的程序和压缩前的程序一样,无需解压仍然能够正常地运行,这种压缩方法称之为带壳压缩,压缩包含两个部分:

  • 在程序开头或其他合适的地方插入解压代码;
  • 将程序的其他部分压缩。

执行时,也包含两个部分:

  • 首先执行的是程序开头的插入的解压代码,将原来的程序在内存中解压出来;
  • 再执行解压后的程序。 也就是说,upx 在程序执行时,会有额外的解压动作,不过这个耗时几乎可以忽略。 如果对编译后的体积没什么要求的情况下,可以不使用 upx 来压缩。一般在服务器端独立运行的后台服务,无需压缩体积。

最后

https://stackoverflow.com/questions/3861634/how-to-reduce-go-compiled-file-size[4] 这帖子里面有很多有意思的答案,

  • 比如用c语言跟go语言实现相同的功能(小demo)c语言生成的可执行大小是 go 语言的1/20(为什么呢?)
  • 在Go语言中我们使用 println 来替代 fmt.println 就能避免引入fmt包,进一步缩小体积。

引用链接

[1]重点考虑: https://go.dev/doc/faq#creating_a_new_language

[2]How Does the Go Compiler Reduce Binary File Size?: https://levelup.gitconnected.com/smart-go-compiler-slimming-bf6a03a7a5dc

[3]UPX: https://upx.github.io/

[4]https://stackoverflow.com/questions/3861634/how-to-reduce-go-compiled-file-size

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 萝卜要加油 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 消除调试信息
  • 使用 upx
    • 单独使用upx 压缩
    • upx + 编译器选项
    • upx 的原理
  • 最后
    • 引用链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档