Go - 基於逃逸分析來提升程式效能
阿新 • • 發佈:2021-10-30
目錄
前言
為什麼需要了解逃逸分析?
因為我們想要提升程式效能,通過逃逸分析我們能夠知道變數是分配到堆上還是棧上,如果分配到棧上,記憶體的分配和釋放都是由編譯器進行管理,分配和釋放的速度非常快,如果分配到堆上,堆不像棧那樣可以自動清理,它會引起頻繁地進行垃圾回收(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
棧空間不足,會發生逃逸,優化方案儘量設定容量,如果容量實在過大那就沒辦法了。
小結
- 逃逸分析是編譯器在靜態編譯時完成的。
- 逃逸分析後可以確定哪些變數可以分配在棧上,棧的效能好。
以上,希望對你能夠有所幫助。
推薦閱讀
- Go - 使用 sync.Pool 來減少 GC 壓力
- Go - 使用 options 設計模式
- Go - json.Unmarshal 遇到的小坑
- Go - 兩個在開發中需注意的小點
- Go - time.RFC3339 時間格式化
作者:新亮筆記(關注公眾號,可申請新增微信好友)
出處:https://www.cnblogs.com/xinliangcoder
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。