dseax40600 2018-07-25 12:20
浏览 373
已采纳

'go run -gcflags -m xxx.go'的输出是什么意思

Trying to check whether a local variable is allocated on heap or stack in go program, and can't be sure the meaning of some output from go's gc.


Code

variable_heap_stack.go:

// variable heap & stack learn,
// run with:
//  go run -gcflags -m xxx.go
package main

import "fmt"

func getPointerOfLocalVar() *int {
    x := 10 // go will put it into heap,
    return &x
}

// heap & stack test,
func heapStackTest() {
    px := getPointerOfLocalVar()
    fmt.Printf("x: %d
", *px)

    y := 20 // go will put it into stack,
    fmt.Printf("y: %d
", y)
}

func main() {
    heapStackTest()
}

Execute:

go run -gcflags -m variable_heap_stack.go

Output:

# command-line-arguments
./variable_heap_stack.go:8:6: can inline getPointerOfLocalVar
./variable_heap_stack.go:15:28: inlining call to getPointerOfLocalVar
./variable_heap_stack.go:10:9: &x escapes to heap
./variable_heap_stack.go:9:6: moved to heap: x
./variable_heap_stack.go:16:24: *px escapes to heap
./variable_heap_stack.go:19:13: y escapes to heap
./variable_heap_stack.go:15:28: heapStackTest &x does not escape
./variable_heap_stack.go:16:12: heapStackTest ... argument does not escape
./variable_heap_stack.go:19:12: heapStackTest ... argument does not escape
x: 10
y: 20

Questions

  • What does escapes to heap mean? Is it going to heap or not?
  • moved to heap, this means move to heap, right? What's the difference with the above one?
  • The y variable is local, no one refer to it after function returns, but there still got a line y escapes to heap, why was that?
  • 写回答

1条回答 默认 最新

  • dongtao9158 2018-07-25 13:41
    关注

    What does escapes to heap mean? Is it going to heap or not?

    This means the value indicated in the message leaves the "boundaries" of the function, and as such, it cannot be guaranteed what happens with it outside of the function, so if the value is a pointer or reference (but only then), the pointed or referenced value must be allocated on the heap.

    You can think of escapes to heap as a debug message, it does not indicate that one of your variables is "relocated" to the heap.

    So to put it simple, "escapes to heap" is analogous to the term: "it leaves the function", or "it is passed outside of the function".

    As an example this line:

    ./variable_heap_stack.go:16:24: *px escapes to heap
    

    Says that the value *px is passed outside of the function, namely as an argument to fmt.Printf() in this line:

    fmt.Printf("x: %d
    ", *px)
    

    moved to heap, this means move to heap, right? What's the difference with the above one?

    This indicates that the compiler decided to move the variable indicated in the message to the heap, because it might be referenced outside of the function, and thus it must survive the function. And since stack-allocated values may become invalid once you return from the function, for the indicated variable to be valid after the function returns, it must be on the heap.

    Moved to heap is a direct announcement that one of your variables was indeed "relocated" to the heap. Note: "relocated" means that the variable will be allocated on the heap in the first place, actual "relocation" will not happen in any case.

    The y variable is local, no one refer to it after function returns, but there still got a line y escapes to heap, why was that?

    As mentioned before, this does not mean y is relocated to heap, it only means the value y is passed outside of the function, namely as a parameter to fmt.Printf() in this line:

    fmt.Printf("y: %d
    ", y)
    

    y will not be moved to heap just because of this, there is no need, as it is passed to fmt.Printf() by making a copy of its value, and fmt.Printf() will have no way of reaching your y local variable.

    Tip:

    You can get more details about optimization decisions and escape analysis by passing -m twice like this:

    go run -gcflags='-m -m' variable_heap_stack.go
    

    Then the output of this command will be:

    ./variable_heap_stack.go:8:6: can inline getPointerOfLocalVar as: func() *int { x := 10; return &x }
    ./variable_heap_stack.go:14:6: cannot inline heapStackTest: non-leaf function
    ./variable_heap_stack.go:15:28: inlining call to getPointerOfLocalVar func() *int { x := 10; return &x }
    ./variable_heap_stack.go:22:6: cannot inline main: non-leaf function
    ./variable_heap_stack.go:10:9: &x escapes to heap
    ./variable_heap_stack.go:10:9:         from ~r0 (return) at ./variable_heap_stack.go:10:2
    ./variable_heap_stack.go:9:2: moved to heap: x
    ./variable_heap_stack.go:16:24: *px escapes to heap
    ./variable_heap_stack.go:16:24:        from ... argument (arg to ...) at ./variable_heap_stack.go:16:12
    ./variable_heap_stack.go:16:24:        from *(... argument) (indirection) at ./variable_heap_stack.go:16:12
    ./variable_heap_stack.go:16:24:        from ... argument (passed to call[argument content escapes]) at ./variable_heap_stack.go:16:12
    ./variable_heap_stack.go:19:13: y escapes to heap
    ./variable_heap_stack.go:19:13:        from ... argument (arg to ...) at ./variable_heap_stack.go:19:12
    ./variable_heap_stack.go:19:13:        from *(... argument) (indirection) at ./variable_heap_stack.go:19:12
    ./variable_heap_stack.go:19:13:        from ... argument (passed to call[argument content escapes]) at ./variable_heap_stack.go:19:12
    ./variable_heap_stack.go:15:28: heapStackTest &x does not escape
    ./variable_heap_stack.go:16:12: heapStackTest ... argument does not escape
    ./variable_heap_stack.go:19:12: heapStackTest ... argument does not escape
    x: 10
    y: 20
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
  • ¥20 Python安装cvxpy库出问题
  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥15 python天天向上类似问题,但没有清零
  • ¥30 3天&7天&&15天&销量如何统计同一行
  • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
  • ¥15 C#调用python代码(python带有库)
  • ¥15 活动选择题。最多可以参加几个项目?
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题