go语言编译器会自动决定把一个变量放在栈还是放在堆,编译器会做逃逸分析(escape analysis),当发现变量的作用域没有跑出函数范围,就可以在栈上,反之则必须分配在堆。
go语言声称这样可以释放程序员关于内存的使用限制,更多的让程序员关注于程序功能逻辑本身。
我们再看如下代码:
package main
func foo(arg_val int) (*int) {
var foo_val1 int = 11;
var foo_val2 int = 12;
var foo_val3 int = 13;
var foo_val4 int = 14;
var foo_val5 int = 15;
//此处循环是防止go编译器将foo优化成inline(内联函数)
//如果是内联函数,main调用foo将是原地展开,所以foo_val1-5相当于main作用域的变量
//即使foo_val3发生逃逸,地址与其他也是连续的
for i := 0; i < 5; i++ {
println(&arg_val, &foo_val1, &foo_val2, &foo_val3, &foo_val4, &foo_val5)
}
//返回foo_val3给main函数
return &foo_val3;
}
func main() {
main_val := foo(666)
println(*main_val, main_val)
}
我们运行一下:
$ go run pro_2.go
0xc000030758 0xc000030738 0xc000030730 0xc000082000 0xc000030728 0xc000030720
0xc000030758 0xc000030738 0xc000030730 0xc000082000 0xc000030728 0xc000030720
0xc000030758 0xc000030738 0xc000030730 0xc000082000 0xc000030728 0xc000030720
0xc000030758 0xc000030738 0xc000030730 0xc000082000 0xc000030728 0xc000030720
0xc000030758 0xc000030738 0xc000030730 0xc000082000 0xc000030728 0xc000030720
13 0xc000082000
foo_val30xc000082000
go tool compile
$ go tool compile -m pro_2.go
pro_2.go:24:6: can inline main
pro_2.go:7:9: moved to heap: foo_val3
foo_val3foo_val3