提问人:Evert Heylen 提问时间:11/22/2014 最后编辑:CommunityEvert Heylen 更新时间:1/4/2015 访问量:2237
为什么使用 gccgo 构建的二进制文件更小(以及其他差异?
Why are binaries built with gccgo smaller (among other differences?)
问:
我一直在尝试 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:更多的优化,更多的处理器。
我认为更多的优化意味着更快的二进制文件,同时需要更多的时间来编译......
这三种模式的原因是什么?
答:
8赞
Stephen Weinberg
11/22/2014
#1
大小不同,因为 gc 会生成静态二进制文件,而 gccgo 会链接到 libgo。这意味着整个运行时(调度器、垃圾回收器、映射、通道)的代码不在 gccgo 创建的最终二进制文件中。
编译速度当然有利于 gc。GC 在构建时考虑了编译速度。它通常还会生成较少的优化代码,并且需要执行的工作也较少。
现在谈谈为什么 gc 仍然更快。事实是,它们都不总是比另一个快。例如,尝试对文件进行 md5 处理,GCCGO 的速度会快一个数量级。尝试实现具有大量通道的东西,gc 肯定会获胜。你不能总是提前知道哪个会成功。GC 往往具有更高效的并发性,而 gccgo 往往更擅长数学。但是,这是您需要根据具体情况进行测试的内容。最好使用 go test 的基准测试系统,而不是时间。
8赞
7 revstwotwotwo
#2
有很多不同之处——bradfitz 在 2014 年 5 月的一次演讲中谈到了其中的一些:
gccgo
可以生成一个动态链接的二进制文件,这使得输出更小,但意味着相关库要安装在目标机器上。没有 go 二进制文件,没有这个要求。libgo
cgo
gccgo
做更多的低级优化,因为它可以使用 的代码生成器和优化器。编写一些数据压缩代码后,gccgo 运行它的速度明显快于 .这些相同的优化使编译器变慢:它正在做更多的工作。gcc
gc
gccgo
支持目标处理器,因此这是使用某些架构(如 SPARC、ARMv8(64 位)或 POWER)的唯一方法。(Canonical 使用它来编译 arm64 和 ppc64 的 Juju 服务编排工具。gcc
gccgo
两者都支持 ARMv7(32 位),但根据 bradfitz 的演讲,它并没有生成最有效的 ARM 代码。gc
gc
- 只有某些优化才有。
gc
- 一个很大的问题是转义分析,其中编译器确定某些变量永远不会“转义”它们被分配的函数,因此可以进行堆栈分配。(因此,令人惊讶的是,如果其返回值没有转义,则可能不会进行堆分配。这样可以减少垃圾回收需要运行的频率。
new(T)
- 另一个是标准库中的汇编文件仅由 链接,因此默认情况下不使用英特尔硬件 CRC32C 之类的东西(您必须专门为 gccgo 提供实现)。
.s
gc
gccgo
- 一个很大的问题是转义分析,其中编译器确定某些变量永远不会“转义”它们被分配的函数,因此可以进行堆栈分配。(因此,令人惊讶的是,如果其返回值没有转义,则可能不会进行堆分配。这样可以减少垃圾回收需要运行的频率。
gc
首先实现新的语言功能,并且通常比最新的 Go 版本早一两个次要版本。gccgo
评论
0赞
twotwotwo
11/22/2014
(制作这个 CW 是因为关于 gc/gccgo 的差异可能有很多话要说,我不是真正的专家,我希望知道更多的人来编辑它。
评论
libgo
ldd
readelf