douge7771 2015-08-23 22:45
浏览 5
已采纳

优化离开堆分配

When I am talking about Go, I am speaking about the gc compiler implementation.

As far as I know, Go performs escape analysis. The following idiom is seen pretty often in Go code:

func NewFoo() *Foo

Escape analysis would notice that Foo escapes NewFoo and allocate Foo on the heap.

This function could also be written as:

func NewFoo(f *Foo)

and would be used like

var f Foo
NewFoo(&f)

In this case, as long as f doesn't escape anywhere else, f could be allocated on the stack.

Now to my actual question.

Would it be possible for the compiler to optimize every foo() *Foo into foo(f *Foo), even possibly over multiple levels where Foo is returned in each?

If not, in what kind of cases does this approach fail?

Thank you in advance.

  • 写回答

2条回答 默认 最新

  • douxing2156 2015-08-24 00:38
    关注

    (Not quite an answer but too big for a comment.)

    From the comments it seems you might be interested in this small example:

    package main
    
    type Foo struct {
        i, j, k int
    }
    
    func NewFoo() *Foo {
        return &Foo{i: 42}
    }
    
    func F1() {
        f := NewFoo()
        f.i++
    }
    
    func main() {
        F1()
    }
    

    On Go1.5 running go build -gcflags="-m" gives:

    ./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
    

    So it inlines NewFoo into F1 into main (and says that it could further inline main if someone was to call it). Although it does say that in NewFoo itself &Foo escapes, it does not escape when inlined.

    The output from go build -gcflags="-m -S" confirms this with a main initializing the object on the stack and not doing any function calls.

    Of course this is a very simple example and any complications (e.g. calling fmt.Print with f) could easily cause it to escape. In general, you shouldn't worry about this too much unless profiling has told you that you have a problem area(s) and you are trying to optimize a specific section of code. Idiomatic and readable code should trump optimization.

    Also note that using go test -bench -benchmem (or preferably using testing.B's ReportAllocs method) can report on allocations of benchmarked code which can help identify something doing more allocations than expected/desired.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了
  • ¥50 切换TabTip键盘的输入法
  • ¥15 可否在不同线程中调用封装数据库操作的类
  • ¥15 微带串馈天线阵列每个阵元宽度计算
  • ¥15 keil的map文件中Image component sizes各项意思
  • ¥20 求个正点原子stm32f407开发版的贪吃蛇游戏
  • ¥15 划分vlan后,链路不通了?
  • ¥20 求各位懂行的人,注册表能不能看到usb使用得具体信息,干了什么,传输了什么数据