我一直在尝试gc和gccgo,但遇到了一些奇怪的现象。

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

$ 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程序(虽然不那么广泛),但它们都表现出相同的行为。

    这似乎与this answer的陈述相矛盾:



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

    这三种模式是什么原因?

    最佳答案

    有很多差异-bradfitz talked about some of them in a May 2014 talk:

  • gccgo可以生成一个二进制文件,该二进制文件可以动态链接到libgo,这会使输出变小,但意味着要在目标计算机上安装相关的库。没有cgo的二进制文件没有此要求。
  • gccgo进行了更多的低级优化,因为它可以使用gcc的代码生成器和优化器。编写一些数据压缩代码后,gccgo的运行速度明显比gc快。相同的优化也使编译器变慢:它正在做更多的工作。
  • gccgo支持gcc所支持的目标处理器,因此这是进入某些架构(如SPARC,ARMv8(64位)或POWER)的唯一方法。 (规范使用它来为arm64和ppc64编译其Juju服务编排工具。)
  • gccgogc都支持ARMv7(32位),但是根据bradfitz的说法,gc不会生成最有效的ARM代码。
  • 只有gc才有某些优化。
  • 很大的一个是escape analysis,其中编译器确定某些变量将永远不会“逃避”分配它们的函数,因此可以对其进行堆栈分配。 (因此,令人惊讶的是,如果new(T)的返回值没有转义,它可能不会进行堆分配。)这减少了垃圾收集运行的频率。
  • 另一个是标准库中的.s汇编器文件仅通过gc链接,因此gccgo默认不使用诸如Intel硬件CRC32C之类的东西(您必须提供专门针对gccgo的实现)。
  • gc首先实现新的语言功能,通常比最新的gccgo少一两个Go版本。
  • 10-07 17:01