【发布时间】:2019-07-20 18:39:24
【问题描述】:
编辑/澄清:
我似乎没有在这里解释自己。我不是在批评 Go,或者它的运行时,或者可执行文件很大的事实。我也不是想说 Go 不好,而 C 好。
我只是指出编译后的可执行文件似乎总是至少在 1MB 左右(大概这是运行时开销),并且无论使用情况如何,导入一个包似乎都会将整个包放入其中。
我的实际问题基本上是这 2 点是默认行为还是唯一行为?我给出了一些 C 程序示例,它们在代码方面与 Go 程序等效,但是我为它们仔细挑选了编译器和链接器标志以避免与任何外部 C 运行时链接(我用Dependency Walker 验证了这一点,只是为了确定)。 C 示例的目的是展示实际代码有多小,同时也展示了您确实需要某些东西并且只导入您需要的东西的情况。
我实际上认为这种行为(把所有东西都放在里面以防万一)是一个很好的默认设置,但我认为可能有一些编译器或链接器标志来改变它。现在,我认为说您不想要运行时或其中的一部分是不明智的。但是,我认为选择性地包含一个包的某些部分并不是一件奇怪的事情。让我解释一下:
假设我们使用 C/C++ 编写代码,并且包含一个包含大量函数的巨大头文件,但我们只使用了其中的一小部分。在这种情况下,可能会得到一个不包含该头文件中任何未使用代码的可执行文件。 (现实世界的例子:一个支持 2D/3D/4D 向量和矩阵、四元数等的数学库。所有这些都有 2 个版本,一个用于 32 位浮点数,一个用于 64 位浮点数 + 从一个到另一个的转换)
这就是我一直在寻找的东西。我完全理解这样做在某些情况下可能会导致问题,但仍然如此。并不是说 Go 没有其他可能导致严重问题的东西。他们有“不安全”的包,如果你需要它就在那里,但它就像“使用风险自负”的包。
原始问题:
在使用 Go (golang) 一段时间后,我决定研究它生成的可执行文件。我看到我的项目仅针对可执行文件就超过 4.5MB,而另一个在复杂性和范围上相似但用 C/C++ 编写(使用 MSVC 编译)的项目不到 100KB。
所以我决定尝试一些事情。我用 C 和 Go 编写了非常愚蠢和死的简单程序来比较输出。 对于 C,我使用 MSVC,在发布模式下编译 64 位可执行文件,而不与 C 运行时链接(据我了解,在我看来,Go 可执行文件仅在使用 CGO 时才链接)
第一次运行:一个简单的无限循环,就是这样。没有打印,没有与操作系统的交互,什么都没有。
C:
#include "windows.h"
int main()
{
while (true);
}
void mainCRTStartup()
{
main();
}
去:
package main
func main() {
for {
}
}
结果:
C : 3KB 可执行文件。不依赖任何东西
GO:1,057 KB 可执行文件。依赖于 KERNEL32.DLL 中的 29 个过程
那里有很大的不同,但我认为这可能不公平。所以接下来的测试我决定去掉循环,只写一个程序,立即返回,退出代码为 13:
C:
#include "windows.h"
int main()
{
return 13;
}
void mainCRTStartup()
{
ExitProcess(main());
}
去:
package main
import "os"
func main() {
os.Exit(13)
}
结果:
C:4KB 可执行文件。取决于 KERNEL32.DLL 中的 1 个过程
GO:1,281 KB 可执行文件。依赖于 KERNEL32.DLL 中的 31 个过程
Go 可执行文件似乎“臃肿”。据我了解,与 C 不同,Go 将相当多的运行时代码放入可执行文件中,这是可以理解的,但不足以解释大小。
此外,Go 似乎在包粒度中工作。我的意思是它不会塞进你不使用的可执行包中,但是如果你导入一个包,你会得到它的全部,即使你只需要一个小子集,即使你根本不使用它.例如,只导入“fmt”而不调用任何内容,会将之前的可执行文件从 1,281KB 扩展到 1,777 KB。
我是否遗漏了一些类似 Go 编译器的标志来告诉它不那么臃肿(我知道有很多标志可以设置,也可以给本机编译器和链接器提供标志,但我还没有找到这个具体来说)或者它只是在 2019 年不再有人关心的事情,因为几兆字节真的是什么?
【问题讨论】:
-
"Go 将相当多的运行时代码放入可执行文件中,这可以理解,但不足以解释大小。"你怎么看?您确定运行时“应该”采用什么大小?
-
虽然一般来说 - 是的,按照现代标准,1MB 很小,与 .NET Core 应用程序的独立构建(例如 50MB+)相比是有利的。
-
这也不是真正的“在 Windows 上”。 Go 特定的所有内容都静态链接在每个平台上。
-
简短的回答是 Go 总是包含 整个 运行时,包括像 GC 和堆栈跟踪这样的东西。它没有专门的优化模式,旨在使
"Hello, World"更小。 -
@Adrian 抱歉,如果我不清楚。我并不是在批评运行时的大小。我的意思是,除了运行时大小本身之外,与 C 等效项相比,Go 可执行文件似乎仍然很大。
标签: go binaryfiles