3 回答
TA贡献1820条经验 获得超9个赞
指针可能会转义到堆中,也可能不转义,具体取决于您的使用案例。编译器非常智能。例如,给定:
type Person struct {
b, c int
}
func foo(b, c int) int {
bob := &Person{b, c}
return bob.b
}
该函数将编译为:foo
TEXT "".foo(SB)
MOVQ "".b+8(SP), AX
MOVQ AX, "".~r2+24(SP)
RET
它全部位于此处的堆栈上,因为即使它是指针,它也不会逃脱此函数的作用域。bob
但是,如果我们考虑轻微的(尽管是人为的)修改:
var globalBob *Person
func foo(b, c int) int {
bob := &Person{b, c}
globalBob = bob
return bob.b
}
然后转义,并将编译为:bobfoo
TEXT "".foo(SB), ABIInternal, $24-24
MOVQ (TLS), CX
CMPQ SP, 16(CX)
PCDATA $0, $-2
JLS foo_pc115
PCDATA $0, $-1
SUBQ $24, SP
MOVQ BP, 16(SP)
LEAQ 16(SP), BP
LEAQ type."".Person(SB), AX
MOVQ AX, (SP)
PCDATA $1, $0
CALL runtime.newobject(SB)
MOVQ 8(SP), AX
MOVQ "".b+32(SP), CX
MOVQ CX, (AX)
MOVQ "".c+40(SP), CX
MOVQ CX, 8(AX)
PCDATA $0, $-2
CMPL runtime.writeBarrier(SB), $0
JNE foo_pc101
MOVQ AX, "".globalBob(SB)
foo_pc83:
PCDATA $0, $-1
MOVQ (AX), AX
MOVQ AX, "".~r2+48(SP)
MOVQ 16(SP), BP
ADDQ $24, SP
RET
如您所见,它调用 .newobject
这些反汇编列表由 https://godbolt.org/ 生成,在 amd64 上为 go 1.16 生成
TA贡献1851条经验 获得超5个赞
是将内存分配给堆栈上还是“转义”到堆中,完全取决于您如何使用内存,而不是如何声明变量。
如果返回指向堆栈分配变量的指针(例如 C),则当您尝试使用它时,指针的值将无效。这在 Go 中是不可能的,因为您无法显式告诉 Go 将变量放置在何处。它在选择正确的位置方面做得很好,如果它看到对内存 blob 的引用可能位于堆栈帧之外,它将确保在堆上进行分配。
golang可以用这样的符号分配内存吗?
var bob * Person = & Person {2, 3}
或者指针始终指向堆栈
不能说这行代码“总是”指向堆栈,但它有时可能会,所以是的,它可能会分配内存(在堆上)。
同样,这不是关于那行代码,而是关于它之后会发生什么。如果返回值 (对象的地址),则无法在堆栈上分配它,因为返回的地址将指向回收的内存。bob
Person
TA贡献1872条经验 获得超3个赞
简而言之,如果编译器可以证明该值可以在堆栈上安全地创建,那么它将(可能)在堆栈上创建。否则,它将在堆上分配。
编译器必须执行这些证明的工具非常好,但它并不总是正确。然而,大多数时候,担心它的成本与收益并没有真正的好处。
- 3 回答
- 0 关注
- 103 浏览
添加回答
举报