golang記憶體逃逸分析
阿新 • • 發佈:2020-12-10
逃逸分析在編譯階段完成,目的是決定記憶體分配地址是棧還是堆:編譯時通過 go build -gcflags=-m 可以檢視逃逸物件
1、關於堆和棧
棧可以簡單理解成一次函式呼叫內部申請到的記憶體,它們會隨著函式的返回把記憶體還給系統。
在棧上申請的記憶體 :函式返回直接釋放,不會引起垃圾回收,對效能沒有影響。
在堆上申請的物件生命週期可以超出函式呼叫的作用域,需要gc進行回收。
2、看幾個demo
1、申請臨時變數不會逃逸
func a() { t := make([]int, 10) // 這裡是不會逃逸到堆上的 if len(t) == 1 { } }
2、函式結尾時把slice給返回了,會逃逸到堆上,因為編譯器認為該物件後續會被使用
func a() []int {
t := make([]int, 10) // 返回切片,則會逃逸
return t
}
3、同2,返回指標和返回引用型別一樣,會造成逃逸
type a struct{}
func NewA() *a {
return &a{} // 返回指標會逃逸
}
4、因為申請空間過大的物件,也會逃逸
func a() { t := make([]int, 10) t2 := make([]int, 10000) if len(t) == 0 || len(t2) == 0 { } }
這兩個臨時變數,都沒有作為返回值,但我們看到t2逃逸了。這裡我們知道:申請空間過大的物件,也會逃逸
5、變長空間申請,會造成逃逸
func a() {
t := 10
t2 := make([]int, t) // 這裡還是會逃逸
if len(t2) == 0 {
}
}
./main.go:11:12: make([]int, t) escapes to heap
編譯時發現t2又逃逸了,原因是編譯器不知道需要分配多大的空間給t2,編譯器其實看到的cap是變數t,而不是10
3、以上總結
- 棧記憶體不需要gc,函式結束後回收
-
堆上分配的記憶體使用完畢會交給GC處理
-
逃逸分析在編譯階段完成,目的是決定物件分配到棧還是堆