> ## Content Index
> Fetch the complete content index at: https://huizhou92.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Go 高性能编程EP2:  通过upx 缩小可执行二进制文件的体积
- URL: https://huizhou92.com/go-gao-xing-neng-bian-cheng-ep2-tong-guo-upx-suo-xiao-ke-zhi-xing-er-jin-zhi-wen-jian-de-ti-ji/
- Published: 2024-07-02T07:01:44.000Z
- Updated: 2026-09-06T11:40:00.000Z
- Description: 探索如何通过使用UPX和Go编译器选项来显著减小Go语言编译生成的可执行二进制文件的大小。了解去除调试信息的技巧，以及UPX的压缩效果，将原本6.5M的文件压缩至1.4M，节省高达80%的存储空间。本文为追求高效和精简的Go程序员提供实用方法，掌握优化技巧，提升开发效率！
- Author: huizhou92
- Tags: tech, go, #lang-zh-cn

我们都知道，Go有一个很重要的特点，那就是它的编译速度非常快，编译速度是Go语言设计的时候就[重点考虑](https://go.dev/doc/faq?ref=huizhou92.com#creating%5Fa%5Fnew%5Flanguage)的问题. 但是您有没有观察过Go语言编译后的二进制可执行文件的大小？我们先用一个简单的http server 的例子来看看。

> This article was first published in the Medium MPP plan. If you are a Medium user, please follow me on [Medium](https://medium.huizhou92.com/?ref=huizhou92.com). Thank you very much.

```go
import (  
    "fmt"  
    "net/http"
    )  
func main() {  
    // 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

```shell
➜  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?](https://levelup.gitconnected.com/smart-go-compiler-slimming-bf6a03a7a5dc?ref=huizhou92.com)

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

## 消除调试信息

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

```shell
➜  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](https://upx.github.io/?ref=huizhou92.com) 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

```shell
brew install upx

```

### 单独使用upx 压缩

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

```shell
➜  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"

```shell
➜  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](https://stackoverflow.com/questions/3861634/how-to-reduce-go-compiled-file-size?ref=huizhou92.com)  
这帖子里面有很多有意思的答案，

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