我在我的Linux机器上编写了一个Hello world Go程序,并生成了本地可执行文件。但是我惊讶地看到这个简单的Hello world Go程序的大小,它高达1.9MB!
为什么这么简单的Go程序的可执行文件如此庞大?
我在我的Linux机器上编写了一个Hello world Go程序,并生成了本地可执行文件。但是我惊讶地看到这个简单的Hello world Go程序的大小,它高达1.9MB!
为什么这么简单的Go程序的可执行文件如此庞大?
5l
,6l
和8l
)执行静态链接。因此,所有Go二进制文件都包含Go运行时,以及支持动态类型检查、反射甚至panic时堆栈跟踪所需的运行时类型信息。printf
的实现。相应地,使用fmt.Printf
的等效Go程序大约为1.9MB,但这包括更强大的运行时支持和类型信息。"Hello World"
文本的fmt
包的实现(以及它的依赖项)。fmt.Println("Hello World! Again")
并重新编译。结果不会是2倍的1.9MB,而仍然只有1.9MB!是的,因为所有使用的库(fmt
及其依赖项)和运行时已经添加到可执行文件中(所以只需添加几个字节即可打印您刚刚添加的第二个文本)。考虑以下程序:
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
如果我在我的Linux AMD64机器(Go 1.9)上构建它,就像这样:
$ go build
$ ls -la helloworld
-rwxr-xr-x 1 janf group 2029206 Sep 11 16:58 helloworld
我收到了一个大约2MB大小的二进制文件。
这是由于我们正在使用相当庞大的“fmt”包,这已经在其他答案中解释过了,但二进制文件也没有被剥离,这意味着符号表仍然存在。如果我们改为指示编译器剥离二进制文件,它将变得更小:
$ go build -ldflags "-s -w"
$ ls -la helloworld
-rwxr-xr-x 1 janf group 1323616 Sep 11 17:01 helloworld
然而,如果我们重写程序并使用内置函数print来代替fmt.Println,就像这样:
package main
func main() {
print("Hello World!\n")
}
然后编译它:
$ go build -ldflags "-s -w"
$ ls -la helloworld
-rwxr-xr-x 1 janf group 714176 Sep 11 17:06 helloworld
我们最终得到了一个更小的二进制文件。这已经是我们不借助像UPX打包这样的技巧所能做到的最小值了,因此Go运行时的开销大约为700Kb。
考虑到编译器、汇编器、链接器和运行时在1.5中将完全使用Go语言编写,您可以期待进一步的优化。因为我们不将这些名称写入符号表中。
runtime.pclntab
。请参见Raphael ‘kena’ Poss的 "Why are my Go executable files so large? Size visualization of Go executables using D3"。
It is not too well documented however this comment from the Go source code suggests its purpose:
// A LineTable is a data structure mapping program counters to line numbers.
The purpose of this data structure is to enable the Go runtime system to produce descriptive stack traces upon a crash or upon internal requests via the
runtime.GetStack
API.So it seems useful. But why is it so large?
The URL https://golang.org/s/go12symtab hidden in the aforelinked source file redirects to a document that explains what happened between Go 1.0 and 1.2. To paraphrase:
prior to 1.2, the Go linker was emitting a compressed line table, and the program would decompress it upon initialization at run-time.
in Go 1.2, a decision was made to pre-expand the line table in the executable file into its final format suitable for direct use at run-time, without an additional decompression step.
In other words, the Go team decided to make executable files larger to save up on initialization time.
Also, looking at the data structure, it appears that its overall size in compiled binaries is super-linear in the number of functions in the program, in addition to how large each function is.
dotnet publish -r win-x64 -p:publishsinglefile=true -p:publishreadytorun=true -p:publishtrimmed=true
命令生成一个大小约为26MB的二进制文件! - Jalal