Eri*_*ang 3 go compiler-optimization escape-analysis
尝试检查 go 程序中局部变量是否分配在堆或堆栈上,并且无法确定 go 的 gc 的某些输出的含义。
变量_堆_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\n", *px)
y := 20 // go will put it into stack,
fmt.Printf("y: %d\n", y)
}
func main() {
heapStackTest()
}
Run Code Online (Sandbox Code Playgroud)
执行:
去运行-gcflags -mvariable_heap_stack.go
输出:
# 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
Run Code Online (Sandbox Code Playgroud)
escapes to heap
意思?它会堆还是不会堆?moved to heap
,这意味着移动到堆,对吗?和上面的有什么区别呢?y
变量是局部变量,函数返回后没有人引用它,但仍然有一行y escapes to heap
,这是为什么?这是什么
escapes to heap
意思?它会堆还是不会堆?
这意味着消息中指示的值离开了函数的“边界”,因此,不能保证它在函数之外会发生什么,因此如果该值是指针或引用(但只有这样),则指向或引用的值必须分配在堆上。
您可以将其视为escapes to heap
一条调试消息,它并不表明您的变量之一已“重新定位”到堆。
因此,简单地说,“转义到堆”类似于术语:“它离开函数”,或“它被传递到函数外部”。
作为示例这一行:
./variable_heap_stack.go:16:24: *px escapes to heap
Run Code Online (Sandbox Code Playgroud)
表示该值*px
在函数外部传递,即作为fmt.Printf()
此行中的参数:
fmt.Printf("x: %d\n", *px)
Run Code Online (Sandbox Code Playgroud)
moved to heap
,这意味着移动到堆,对吗?和上面的有什么区别呢?
这表明编译器决定将消息中指示的变量移动到堆中,因为它可能在函数外部被引用,因此它必须在函数中生存。由于一旦从函数返回,堆栈分配的值可能会变得无效,因此为了使指示的变量在函数返回后有效,它必须位于堆上。
Moved to heap
是直接声明您的变量之一确实已“重新定位”到堆。注意:“重定位”意味着变量将首先在堆上分配,任何情况下都不会发生实际的“重定位”。
该
y
变量是局部变量,函数返回后没有人引用它,但仍然有一行y escapes to heap
,这是为什么?
如前所述,这并不意味着y
重定位到堆,它仅意味着该值y
被传递到函数外部,即作为fmt.Printf()
此行中的参数:
fmt.Printf("y: %d\n", y)
Run Code Online (Sandbox Code Playgroud)
y
不会仅仅因为这个而被移动到堆,没有必要,因为它是fmt.Printf()
通过复制其值来传递的,并且fmt.Printf()
无法到达您的y
局部变量。
请注意,由于fmt.Printf()
需要 type 的值...any
,因此变量y
将被包装在接口值中,然后包装在切片中,而将其包装在接口值中是导致“转义”的原因。int
如果您将其传递给期望或什至的函数...int
,则不会发生转义,因为这只会传递该int
值,而不对变量有任何引用或连接y
。
提示:
您可以通过-m
像这样传递两次来获取有关优化决策和逃逸分析的更多详细信息:
go run -gcflags='-m -m' variable_heap_stack.go
Run Code Online (Sandbox Code Playgroud)
那么该命令的输出将是:
./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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3495 次 |
最近记录: |