go语言编译器会自动决定把一个变量放在栈还是放在堆,编译器会做逃逸分析(escape analysis),当发现变量的作用域没有跑出函数范围,就可以在栈上,反之则必须分配在堆。
package mainfunc 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)}输出:0xc000037f58 0xc000037f38 0xc000037f30 0xc00000a028 0xc000037f28 0xc000037f200xc000037f58 0xc000037f38 0xc000037f30 0xc00000a028 0xc000037f28 0xc000037f200xc000037f58 0xc000037f38 0xc000037f30 0xc00000a028 0xc000037f28 0xc000037f200xc000037f58 0xc000037f38 0xc000037f30 0xc00000a028 0xc000037f28 0xc000037f200xc000037f58 0xc000037f38 0xc000037f30 0xc00000a028 0xc000037f28 0xc000037f2013 0xc00000a028
我们能看到foo_val3是返回给main的局部变量, 其中他的地址应该是0xc000082000,很明显与其他的foo_val1、2、3、4不是连续的.
什么是内联函数
简单理解就是编译时把函数的定义替换到调用的位置。
inline int Add(int a, int b){return a + b;}int main(){int num1 = 1;int num2 = 2;int myNum = Add(num1, num2);}//这样的代码内联之后大概就是int main(){int num1 = 1;int num2 = 2;int myNum = num1 + num2;}
在内敛函数中foo_val1-5相当于main作用域的变量,即使foo_val3发生逃逸,地址与其他也是连续的
package mainfunc 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发生逃逸,地址与其他也是连续的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)}输出:0xc000037f68 0xc000037f60 0xc000037f58 0xc000037f50 0xc000037f48 0xc000037f4013 0xc000037f50
