Go 逃逸分析
堆和棧
堆(Heap):
一般來講是人為手動進行管理,手動申請、分配、釋放。堆適合不可預(yù)知大小的內(nèi)存分配,這也意味著為此付出的代價是分配速度較慢,而且會形成內(nèi)存碎片。
棧(Stack):
由編譯器進行管理,自動申請、分配、釋放。一般不會太大,因此棧的分配和回收速度非???;我們常見的函數(shù)參數(shù)(不同平臺允許存放的數(shù)量不同),局部變量等都會存放在棧上。
棧分配內(nèi)存只需要兩個CPU指令:“PUSH”和“RELEASE”,分配和釋放;而堆分配內(nèi)存首先需要去找到一塊大小合適的內(nèi)存塊,之后要通過垃圾回收才能釋放。
通俗比喻的說,棧就如我們?nèi)ワ堭^吃飯,只需要點菜(發(fā)出申請)--》吃吃吃(使用內(nèi)存)--》吃飽就跑剩下的交給飯館(操作系統(tǒng)自動回收),而堆就如在家里做飯,大到家,小到買什么菜,每一個環(huán)節(jié)都需要自己來實現(xiàn),但是自由度會大很多。
什么是逃逸分析
在編譯程序優(yōu)化理論中,逃逸分析是一種確定指針動態(tài)范圍的方法,簡單來說就是分析在程序的哪些地方可以訪問到該指針。
再往簡單的說,Go是通過在編譯器里做逃逸分析(escape analysis)來決定一個對象放棧上還是放堆上,不逃逸的對象放棧上,可能逃逸的放堆上;即我發(fā)現(xiàn)變量在退出函數(shù)后沒有用了,那么就把丟到棧上,畢竟棧上的內(nèi)存分配和回收比堆上快很多;反之,函數(shù)內(nèi)的普通變量經(jīng)過逃逸分析后,發(fā)現(xiàn)在函數(shù)退出后變量還有在其他地方上引用,那就將變量分配在堆上。做到按需分。
為何需要逃逸分析
ok,了解完堆和棧各自的優(yōu)缺點后,我們就可以更好的知道逃逸分析存在的目的了:
減少gc壓力,棧上的變量,隨著函數(shù)退出后系統(tǒng)直接回收,不需要gc標(biāo)記后再清除。
減少內(nèi)存碎片的產(chǎn)生。
減輕分配堆內(nèi)存的開銷,提高程序的運行速度。
如何確定是否逃逸
在Go中通過逃逸分析日志來確定變量是否逃逸,開啟逃逸分析日志:
go run -gcflags '-m -m -m -m -l' main.go
-m 會打印出逃逸分析的優(yōu)化策略,實際上最多總共可以用 4 個 -m,但是信息量較大,一般用 1 個就可以了。
-l 會禁用函數(shù)內(nèi)聯(lián),在這里禁用掉內(nèi)聯(lián)能更好的觀察逃逸情況,減少干擾。
什么情況下會發(fā)生逃逸分析
堆棧占用內(nèi)存
1 指針引用,常見函數(shù)間指針參數(shù)以及返回值
2 interface不明類型的調(diào)用