Go的記憶體逃逸及逃逸分析
Go的記憶體逃逸
分析記憶體逃逸之前要搞清楚一件事 我們撰寫的程式中的函式和區域變數默認是存放在堆疊上的(補充一點堆上存盤的資料的指標 是存放在堆疊上的 因為指標的大小是可以提前預知的 還有就是Go的基本型別也是存放在堆疊內的), 而其余的變數是存在堆上的, 堆疊是由作業系統層面控制 進行記憶體空間的釋放 , 堆默認是程式控制的 像c c++ 是需要標明釋放記憶體空間的位置 , 堆疊的運行速度遠大于堆 . 擁有GC的高級語言回收的便是堆中的內容
- Go編譯器查看記憶體逃逸的結果 go build -gcflags=-m xxx.go
- 發生記憶體逃逸的場景
- 函式回傳區域變數是一個指標變數
#
type User struct {
Name string
}
func name(s string) *User {
u := new(User) # 這個變數的型別是 *User 指標變數
u.Name = s
return u
}
func main() {
user := name("kuQi")
fmt.Println(user)
}
# command-line-arguments
./main.go:9:6: can inline name
./main.go:18:14: inlining call to name
./main.go:19:13: inlining call to fmt.Println
./main.go:9:11: leaking param: s
./main.go:10:10: new(User) escapes to heap // 造成逃逸
./main.go:18:14: new(User) escapes to heap // 造成逃逸
./main.go:19:13: []interface {}{...} does not escape
<autogenerated>:1: leaking param content: .this
2.interface的動態型別造成的記憶體逃逸
// fmt.Println 接受的引數就是interface動態型別 編譯器很難確定接收變數的型別 所有會將123這個變數逃逸到堆
func main() {
fmt.Println(123)
}
# command-line-arguments
./main.go:16:6: can inline main
./main.go:20:13: inlining call to fmt.Println
./main.go:20:14: 123 escapes to heap
./main.go:20:13: []interface {}{...} does not escape
<autogenerated>:1: leaking param content: .this
3.閉包函式產生的記憶體逃逸
// 因為函式也是一個指標型別 所以將匿名函式作為回傳值時 也會產生記憶體逃逸 原理類似于 第一個 原因
func BiBao() func() string {
return func() string {
return "test"
}
}
# command-line-arguments
./main.go:24:9: func literal escapes to heap:
./main.go:24:9: flow: ~r0 = &{storage for func literal}:
./main.go:24:9: from func literal (spill) at ./main.go:24:9
./main.go:24:9: from return func literal (return) at ./main.go:24:2
./main.go:24:9: func literal escapes to heap
4.變數大小無法確定 或 堆疊空間不足 引發記憶體逃逸
ulimit -a // ulimit -a 可以看到我們的堆疊空間是8192
-t: cpu time (seconds) unlimited
-f: file size (blocks) unlimited
-d: data seg size (kbytes) unlimited
-s: stack size (kbytes) 8192
-c: core file size (blocks) 0
-v: address space (kbytes) unlimited
-l: locked-in-memory size (kbytes) unlimited
-u: processes 2784
-n: file descriptors 2560
// 超大切片超出堆疊空間 引發的記憶體逃逸
package main
func main() {
s := make([]int, 10000, 10000) // 創建一個超大切片
for index, _ := range s {
s[index] = index
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/434368.html
標籤:Go
