优化堆分配

当我在谈论 Go 时,我在谈论 gc 编译器的实现。

据我所知,Go 执行逃逸分析。在 Go 代码中经常看到以下习语:

func NewFoo() *Foo

转义分析会注意到 Foo 转义了 NewFoo 并在堆上分配了 Foo。

这个函数也可以写成:

func NewFoo(f *Foo)

并且会像

var f Foo
NewFoo(&f)

在这种情况下,只要 f 不在其他任何地方转义,f 就可以在堆栈上分配。

现在我的实际问题。

编译器是否有可能将每个优化foo() *Foofoo(f *Foo),甚至可能在多个级别上优化,其中每个级别都返回 Foo ?

如果不是,这种方法在什么样的情况下会失败?

先感谢您。


波斯汪
浏览 175回答 2
2回答

森栏

在做了一些更多的研究之后,我找到了我想要的东西。我所描述的显然被称为“返回值优化”并且非常可行,这几乎回答了我关于这是否也可以在 Go 中实现的问题。

千万里不及你

(不完全是一个答案,但对于评论来说太大了。)从评论看来你可能对这个小例子感兴趣:package maintype Foo struct {    i, j, k int}func NewFoo() *Foo {    return &Foo{i: 42}}func F1() {    f := NewFoo()    f.i++}func main() {    F1()}在 Go1.5 上运行go build -gcflags="-m"给出:./new.go:7: can inline NewFoo./new.go:11: can inline F1./new.go:12: inlining call to NewFoo./new.go:16: can inline main./new.go:17: inlining call to F1./new.go:17: inlining call to NewFoo./new.go:8: &Foo literal escapes to heap./new.go:12: F1 &Foo literal does not escape./new.go:17: main &Foo literal does not escape因此,内联NewFoo成F1成main(并说,它可能会进一步直列main如果有人是称呼它)。虽然它确实说NewFoo本身会&Foo逃逸,但内联时并不会逃逸。输出通过初始化堆栈上的对象而不执行任何函数调用来go build -gcflags="-m -S"确认这一点main。当然,这是一个非常简单的例子,任何复杂的情况(例如调用fmt.Printwith f)都可能很容易导致它逃逸。一般来说,除非分析告诉您存在问题区域并且您正在尝试优化特定的代码部分,否则您不必担心太多。惯用和可读的代码应该胜过优化。另请注意,使用go test -bench -benchmem(或最好使用testing.B'sReportAllocs方法)可以报告基准代码的分配,这可以帮助识别比预期/期望的分配更多的事情。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go