获取地址并将指针返回到Go中函数内的局部变量会导致编译器将其分配到堆而不是堆栈,以使返回的指针保持有效。
如果我接受并返回结构成员或嵌入式结构的地址会发生什么?
type A struct {
a,b,c int
}
type B struct {
A
d,e,f int
}
func (b *B) get1() *A {
return &b.A
}
func (b *B) get2() *A {
localB := B{}
return &localB.A
}
编译器是否会在堆上分配嵌入式结构A并将B的成员保留在堆栈上?
即使localB.A引用仍在使用中,垃圾收集器是否会收集localB?
如果通过反射访问嵌入式结构,编译器如何确定何时将嵌入式结构保留在堆栈或堆上?
答案 0 :(得分:3)
为什么你甚至想知道这些细节?
引用Go FAQ(强调我的):
从正确的角度来看,你不需要知道。每个变量 只要有引用就存在于Go中。存储 位置由实现选择与语义无关 语言。
和
在当前的编译器中,如果变量的地址被采用,那么 变量是用于在堆上分配的候选。但是,基本的 转义分析可以识别某些情况,而这些变量则不会 过了函数的返回,可以驻留在堆栈上。
编译器和垃圾收集器的行为严格依赖于实现,并且可能会在不同版本之间发生更改。 您不能事件证明您的开始语句始终为真:编译器可能决定根据您的函数的编写或调用方式应用进一步的优化。
答案 1 :(得分:2)
编译器执行escape analysis以确定变量是否可以在创建它的作用域之外使用,在这种情况下,它必须在堆上分配。如果编译器可以确保不会发生这种情况,它会在堆栈上分配变量。
但是,这是编译器的当前行为,但在规范中未提及,因此在将来的任何版本中都可能会更改。