为什么用 gccgo 构建的二进制文件更小

我一直在试验 gc 和 gccgo,我遇到了一些奇怪的行为。


使用我曾经编写的程序来测试一些定理,我得到了以下结果:(为了可读性,我删除了不必要的信息)


$ time go build -compiler gc -o checkprog_gc checkprog.go (x 3)

go build <...>    0.13s user 0.02s system 100% cpu 0.149 total

go build <...>    0.13s user 0.01s system 99%  cpu 0.148 total

go build <...>    0.14s user 0.03s system 100% cpu 0.162 total

 --> average:     0.13s user 0.02s system 100% cpu 0.153 total



$ time go build -compiler gccgo -o checkprog_gccgo checkprog.go (x 3)

go build <...>    0.10s user 0.03s system 96% cpu 0.135 total

go build <...>    0.12s user 0.01s system 96% cpu 0.131 total

go build <...>    0.10s user 0.01s system 92% cpu 0.123 total

 --> average:     0.11s user 0.02s system 95% cpu 0.130 total



$ strip -s -o checkprog_gc_stripped checkprog_gc

$ strip -s -o checkprog_gccgo_stripped checkprog_gccgo


$ ls -l

 1834504 checkprog_gc*

 1336992 checkprog_gc_stripped*

   35072 checkprog_gccgo*

   24192 checkprog_gccgo_stripped*


$ time ./checkprog_gc

./checkprog_gc  6.68s user 0.01s system 100% cpu 6.674 total

./checkprog_gc  6.75s user 0.01s system 100% cpu 6.741 total

./checkprog_gc  6.66s user 0.00s system 100% cpu 6.643 total

 --> average:   6.70s user 0.01s system 100% cpu 6.686 total


$ time ./checkprog_gccgo

./checkprog_gccgo  10.95s user 0.02s system 100% cpu 10.949 total

./checkprog_gccgo  10.98s user 0.01s system 100% cpu 10.964 total

./checkprog_gccgo  10.94s user 0.01s system 100% cpu 10.929 total

 --> average       10.96s user 0.01s system 100% cpu 10.947 total

我可以看到以下模式:


用它构建的二进制文件的gccgo大小要小得多(剥离无助于改变这种差异)

使用构建的二进制文件gc执行速度更快

构建gccgo比使用多一点时间gc

我还测试了其他一些 go 程序(虽然不是那么广泛),但它们都表现出相同的行为。


这似乎与这个答案所说的相矛盾:


简而言之:gccgo:更多优化,更多处理器。


我认为更多的优化意味着更快的二进制文件,同时需要更多的时间来编译......


这三种模式的原因是什么?


倚天杖
浏览 195回答 2
2回答

三国纷争

有很多不同之处——布拉菲茨在 2014 年 5 月的一次谈话中谈到了其中的一些:gccgo可以生成一个动态链接的二进制文件libgo,这使得输出更小,但意味着要在目标机器上安装相关库。cgo没有这个要求的二进制文件。gccgo进行更多的低级优化,因为它可以使用gcc的代码生成器和优化器。编写一些数据压缩代码,gccgo 的运行速度明显快于gc.&nbsp;这些相同的优化使编译器变慢:它正在做更多的工作。gccgo支持目标处理器gcc,因此它是进入某些架构(如 SPARC、ARMv8(64 位)或 POWER)的唯一途径。(Canonical 使用它为 arm64 和 ppc64 编译他们的 Juju 服务编排工具。)gccgo并且gc两者都支持 ARMv7(32 位),但是根据 bradfitz 的说法gc并不能生成最高效的 ARM 代码。有某些优化只有gc。一个重要的问题是转义分析,其中编译器确定某些变量永远不会“转义”分配它们的函数,因此可以进行堆栈分配。(因此,令人惊讶的是,new(T)如果其返回值没有转义,则可能不会进行堆分配。)这减少了垃圾收集需要运行的频率。另一个是.s标准库中的汇编程序文件仅通过 链接gc,因此gccgo默认情况下不使用诸如英特尔硬件 CRC32C 之类的东西(您必须专门为 gccgo 提供实现)。gc首先实现新的语言功能,并且通常比最新的gccgo.

皈依舞

大小不同,因为 gc 生成静态二进制文件,而 gccgo 链接到 libgo。这意味着整个运行时(调度程序、垃圾收集器、映射、通道)的代码不在 gccgo 创建的最终二进制文件中。编译速度当然有利于gc。GC 的构建考虑了编译速度。它还通常会生成较少优化的代码,并且需要执行的工作较少。现在讨论为什么 gc 仍然更快。事实是,它们中的任何一个都不总是比另一个快。例如,尝试 md5 一个文件,GCCGO 会快一个数量级。尝试用很多通道来实现一些东西,gc 肯定会赢。你不能总是提前知道哪个会成功。GC 往往具有更高效的并发性,而 gccgo 往往更擅长数学。但是,这是您需要根据具体情况进行测试的。最好使用 go test 的基准测试系统而不是时间。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go