【问题标题】:Understanding go tool compile and link commands理解 go 工具编译和链接命令
【发布时间】:2017-11-16 13:45:10
【问题描述】:

我了解将高级语言代码转换为机器语言或可执行代码涉及三个步骤,即编译、汇编和链接。

根据 go docs go tool compile 执行以下操作 - It then writes a single object file named for the basename of the first source file with a .o suffix

因此,最终的目标文件必须包含每个文件的机器语言代码(在编译和汇编运行之后)。如果我在 go 文件上传递 go tool compile -S,它显示汇编语言 go 生成。

之后,当我在目标文件上运行 go tool link 时,它必须链接所有需要的目标文件(如果有多个),然后生成最终的机器语言代码(基于 GOOS 和 GOARCH)。它生成一个文件a.out

这里有几个基本问​​题 -

我如何知道哪些变量以及何时将在堆栈和堆中分配内存?如果我为一台机器生成可执行文件并在具有不同架构的另一台机器上运行,这有关系吗?

我的测试程序

package main

func f(a *int, b *int) *int { 

    var c = (*a + *b); 
    var d = c;
    return &d;
}

func main() {
    var a = 2;
    var b = 6;

    f(&a,&b);
}

go tool compile -m -l test.go

的结果
test.go:6: moved to heap: d
test.go:7: &d escapes to heap
test.go:3: f a does not escape
test.go:3: f b does not escape
test.go:14: main &a does not escape
test.go:14: main &b does not escape

【问题讨论】:

  • 您可以确切地看到 Go 工具对 -x 标志的作用。内存分配当然是在运行时。您可以通过打印逃逸分析输出来查看堆栈与堆的区别。
  • 内存分配是指某个变量将被分配堆内存或堆栈内存。我在哪里看到的?
  • 哦,在编译器优化输出中; -m
  • 谢谢@JimB 我做到了并粘贴了上面的结果。

标签: go compiler-construction


【解决方案1】:

内存是在哪一步分配的?

这取决于,一些在链接期间,一些在编译期间,大部分在运行时(还有一些在加载期间)。

我如何知道哪些变量以及何时将在堆栈和堆中分配内存?

特设你根本不知道。编译器决定这一点。如果编译器可以证明一个变量不会转义,它可能会将其保留在堆栈中。谷歌“golang 逃逸分析”。如果你对它感兴趣,有一个标志 -m 可以让编译器输出他的决定。

如果我为一台机器生成可执行文件并在具有不同架构的另一台机器上运行,这有关系吗?

不,只是因为这根本不起作用:可执行文件与架构相关联,不会在不同的架构上运行。

您似乎混淆了编译/链接和内存分配。后者与前两者有很大不同。 (从技术上讲,您的链接程序可能包含内存,并且在加载过程中它可能会变得更多,但这是高度技术性和架构特定的,实际上没有什么可担心的)。

【讨论】:

  • 我确实使用 -m 选项进行了编译。根据输出,如果一个变量转义了一个函数,它被分配在堆上,如果它没有转义,则在堆栈上。但是它并没有说明临时变量 c 的任何内容。用程序编辑我的问题并编译输出。
  • “可执行文件与架构相关联,不会在不同的架构上运行” - 大致准确,但有一些兼容性;例如,windows-386 (32bit) 应该在 windows-amd64 (64bit) 上运行。
  • @Sam 很可能编译器只是优化了 f 的大部分代码。仅仅因为您写var c ... 并不意味着将使用 RAM 中的实际内存,因为可以使用这些东西,例如在寄存器中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 1970-01-01
  • 2015-12-29
  • 1970-01-01
相关资源
最近更新 更多