Go內存逃逸分析


Go的內存逃逸及逃逸分析

Go的內存逃逸

分析內存逃逸之前要搞清楚一件事 我們編寫的程序中的函數局部變量默認是存放在棧上的(補充一點堆上存儲的數據的指針 是存放在棧上的 因為指針的大小是可以提前預知的 還有就是Go的基本類型也是存放在棧內的), 而其余的變量是存在堆上的, 棧是由操作系統層面控制 進行內存空間的釋放 , 堆默認是程序控制的 像c c++ 是需要標明釋放內存空間的位置 , 棧的運行速度遠大於堆 . 擁有GC的高級語言回收的便是堆中的內容

  • Go編譯器查看內存逃逸的結果 go build -gcflags=-m xxx.go
  • 發生內存逃逸的場景
  1. 函數返回局部變量是一個指針變量
# 
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
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM