[英]Go memory allocation - new objects, pointers and escape analysis
我讀到 Golang 語言以一種智能的方式管理 memory。 使用逃逸分析,go 在調用 new 時可能不會分配 memory,反之亦然。 golang 可以用這樣的符號var bob * Person = & Person {2, 3}
分配 memory 。 或者指針總是指向棧
指針可能會逃到堆中,也可能不會,這取決於您的用例。 編譯器非常聰明。 例如給定:
type Person struct {
b, c int
}
func foo(b, c int) int {
bob := &Person{b, c}
return bob.b
}
function foo
將被編譯成:
TEXT "".foo(SB)
MOVQ "".b+8(SP), AX
MOVQ AX, "".~r2+24(SP)
RET
這一切都在堆棧上,因為即使bob
是一個指針,它也不會逃避這個函數的 scope。
但是,如果我們考慮一個輕微的(盡管是人為的)修改:
var globalBob *Person
func foo(b, c int) int {
bob := &Person{b, c}
globalBob = bob
return bob.b
}
然后bob
轉義, foo
將被編譯為:
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
memory 是在堆棧上分配還是“逃逸”到堆上完全取決於您如何使用 memory,而不取決於您如何聲明變量。
如果您返回指向堆棧分配變量的指針,例如 C,則當您嘗試使用指針時,指針的值將無效。 這在 Go 中是不可能的,因為您無法明確告訴 Go 放置變量的位置。 它在選擇正確位置方面做得非常好,如果它發現對 memory 的 blob 的引用可能超出堆棧幀,它將確保分配發生在堆上。
golang可以用這樣的符號分配memory嗎
var bob * Person = & Person {2, 3}
或者指針總是指向棧
那行代碼不能說“總是”指向堆棧,但有時它可能會,所以是的,它可能會分配 memory (在堆上)。
同樣,這不是關於那行代碼,而是關於它之后的內容。 如果返回bob
的值( Person
對象的地址),則無法在堆棧上分配它,因為返回的地址將指向回收的 memory。
簡而言之,如果編譯器可以證明可以在堆棧上安全地創建該值,那么它將(可能)在堆棧上創建。 否則,它將在堆上分配。
編譯器用來做這些證明的工具非常好,但它並不總是正確的。 然而,大多數時候,擔心它的成本與收益並沒有真正的好處。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.