3 回答

TA貢獻1820條經(jīng)驗 獲得超9個贊
指針可能會轉(zhuǎn)義到堆中,也可能不轉(zhuǎn)義,具體取決于您的使用案例。編譯器非常智能。例如,給定:
type Person struct {
b, c int
}
func foo(b, c int) int {
bob := &Person{b, c}
return bob.b
}
該函數(shù)將編譯為:foo
TEXT "".foo(SB)
MOVQ "".b+8(SP), AX
MOVQ AX, "".~r2+24(SP)
RET
它全部位于此處的堆棧上,因為即使它是指針,它也不會逃脫此函數(shù)的作用域。bob
但是,如果我們考慮輕微的(盡管是人為的)修改:
var globalBob *Person
func foo(b, c int) int {
bob := &Person{b, c}
globalBob = bob
return bob.b
}
然后轉(zhuǎn)義,并將編譯為: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
如您所見,它調(diào)用 .newobject
這些反匯編列表由 https://godbolt.org/ 生成,在 amd64 上為 go 1.16 生成

TA貢獻1851條經(jīng)驗 獲得超5個贊
是將內(nèi)存分配給堆棧上還是“轉(zhuǎn)義”到堆中,完全取決于您如何使用內(nèi)存,而不是如何聲明變量。
如果返回指向堆棧分配變量的指針(例如 C),則當您嘗試使用它時,指針的值將無效。這在 Go 中是不可能的,因為您無法顯式告訴 Go 將變量放置在何處。它在選擇正確的位置方面做得很好,如果它看到對內(nèi)存 blob 的引用可能位于堆棧幀之外,它將確保在堆上進行分配。
golang可以用這樣的符號分配內(nèi)存嗎?
var bob * Person = & Person {2, 3}
或者指針始終指向堆棧
不能說這行代碼“總是”指向堆棧,但它有時可能會,所以是的,它可能會分配內(nèi)存(在堆上)。
同樣,這不是關(guān)于那行代碼,而是關(guān)于它之后會發(fā)生什么。如果返回值 (對象的地址),則無法在堆棧上分配它,因為返回的地址將指向回收的內(nèi)存。bob
Person

TA貢獻1872條經(jīng)驗 獲得超4個贊
簡而言之,如果編譯器可以證明該值可以在堆棧上安全地創(chuàng)建,那么它將(可能)在堆棧上創(chuàng)建。否則,它將在堆上分配。
編譯器必須執(zhí)行這些證明的工具非常好,但它并不總是正確。然而,大多數(shù)時候,擔心它的成本與收益并沒有真正的好處。
- 3 回答
- 0 關(guān)注
- 127 瀏覽
添加回答
舉報