英文:
Returning pointer on struct member or embedded struct in Go?
问题
在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吗?
在通过反射访问时,编译器如何确定何时将嵌入的结构体保留在栈上或堆上?
英文:
Taking address and returning pointer to a local variable inside a function in Go causes compiler to allocate it on heap rather than stack, so that returned pointer remains valid.
Now what happens if I take and return address of a struct member or embedded struct ?
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
}
Will compiler allocate embedded struct A on heap and keep members of B on stack ?
Will garbage collector collect localB even if localB.A reference is still in use ?
How can compiler determine when to keep embedded struct on stack or heap in case if it's accessed through reflection ?
答案1
得分: 5
编译器执行逃逸分析来确定变量是否可能在其创建的作用域之外使用,如果是这样,它必须在堆上分配。如果编译器可以确保这种情况不会发生,它就会在栈上分配变量。
然而,这是编译器的当前行为,但在规范中没有提到,所以它可能在任何未来版本中发生变化。
英文:
The compiler performs escape analysis to determine whether a variable may be used outside of the scope in which it is created, in which case it must be allocated on the heap. If the compiler can make sure that this won’t happen, it allocates the variable on the stack.
However, this is the current behaviour of the compiler, but it is not mentioned in the specification, so it may change in any future version.
答案2
得分: 2
你为什么对这些细节感到好奇呢?
引用Go FAQ(我强调):
从正确性的角度来看,你不需要知道。在Go中,只要有引用存在,每个变量都会存在。实现选择的存储位置与语言的语义无关。
并且
在当前的编译器中,如果一个变量的地址被获取,那么该变量就是堆分配的候选对象。然而,基本的逃逸分析可以识别出一些情况,这些情况下这些变量在函数返回后不会继续存在,可以存储在栈上。
编译器和垃圾回收器的行为严格依赖于实现,并且在不同版本中可能会有所变化。
你甚至无法证明你的开头陈述总是正确的:编译器可能会根据函数的编写方式或调用方式决定是否应用进一步的优化。
英文:
Why are you even wondering about these details?
Quoting the Go FAQ (emphasis mine):
> From a correctness standpoint, you don't need to know. Each variable
> in Go exists as long as there are references to it. The storage
> location chosen by the implementation is irrelevant to the semantics
> of the language.
and
> In the current compilers, if a variable has its address taken, that
> variable is a candidate for allocation on the heap. However, a basic
> escape analysis recognizes some cases when such variables will not
> live past the return from the function and can reside on the stack.
The behavior of the compiler and the garbage collector are strictly implementation-dependent, and subject to changes across different releases.
You cannot event prove your opening statement is always true: the compiler may decide to apply further optimization depending on how your function is written or invoked.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论