1. 程式人生 > 其它 >Go - 基於逃逸分析來提升程式效能

Go - 基於逃逸分析來提升程式效能

目錄

前言

為什麼需要了解逃逸分析?

因為我們想要提升程式效能,通過逃逸分析我們能夠知道變數是分配到堆上還是棧上,如果分配到棧上,記憶體的分配和釋放都是由編譯器進行管理,分配和釋放的速度非常快,如果分配到堆上,堆不像棧那樣可以自動清理,它會引起頻繁地進行垃圾回收(GC),而垃圾回收會佔用比較大的系統開銷。

什麼是逃逸分析?

在編譯程式優化理論中,逃逸分析是一種確定指標動態範圍的方法,簡單來說就是分析在程式的哪些地方可以訪問到該指標。

簡單的說,它是在對變數放到堆上還是棧上進行分析,該分析在編譯階段完成。如果一個變數超過了函式呼叫的生命週期,也就是這個變數在函式外部存在引用,編譯器會把這個變數分配到堆上,這時我們就說這個變數發生逃逸了。

如何確定是否逃逸?

go run -gcflags '-m -l' main.go

可能出現逃逸的場景

01

package main

type Student struct {
	Name interface{}
}

func main()  {
	stu := new(Student)
	stu.Name = "tom"

}

分析結果:

go run -gcflags '-m -l' 01.go
# command-line-arguments
./01.go:8:12: new(Student) does not escape
./01.go:9:11: "tom" escapes to heap

interface{} 賦值,會發生逃逸,優化方案是將型別設定為固定型別,例如:string

package main

type Student struct {
	Name string
}

func main()  {
	stu := new(Student)
	stu.Name = "tom"

}

分析結果:

go run -gcflags '-m -l' 01.go
# command-line-arguments
./01.go:8:12: new(Student) does not escape

02

package main

type Student struct {
	Name string
}

func GetStudent() *Student {
	stu := new(Student)
	stu.Name = "tom"
	return stu
}

func main() {
	GetStudent()
}

分析結果:

go run -gcflags '-m -l' 02.go
# command-line-arguments
./02.go:8:12: new(Student) escapes to heap

返回指標型別,會發生逃逸,優化方案視情況而定。

函式傳遞指標和傳值哪個效率高嗎?我們知道傳遞指標可以減少底層值的拷貝,可以提高效率,但是如果拷貝的資料量小,由於指標傳遞會產生逃逸,可能會使用堆,也可能會增加 GC 的負擔,所以傳遞指標不一定是高效的。

不要盲目使用變數指標作為引數,雖然減少了複製,但變數逃逸的開銷可能更大。

03

package main

func main() {
	nums := make([]int, 10000, 10000)

	for i := range nums {
		nums[i] = i
	}
}

分析結果:

go run -gcflags '-m -l' 03.go
# command-line-arguments
./03.go:4:14: make([]int, 10000, 10000) escapes to heap

棧空間不足,會發生逃逸,優化方案儘量設定容量,如果容量實在過大那就沒辦法了。

小結

  1. 逃逸分析是編譯器在靜態編譯時完成的。
  2. 逃逸分析後可以確定哪些變數可以分配在棧上,棧的效能好。

以上,希望對你能夠有所幫助。

推薦閱讀

作者:新亮筆記(關注公眾號,可申請新增微信好友)
出處:https://www.cnblogs.com/xinliangcoder
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。