淺談Golang內存逃逸_第1頁
淺談Golang內存逃逸_第2頁
淺談Golang內存逃逸_第3頁
淺談Golang內存逃逸_第4頁
淺談Golang內存逃逸_第5頁
已閱讀5頁,還剩2頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第淺談Golang內存逃逸目錄1.什么是內存逃逸2.什么是逃逸分析3.小結4.逃逸分析案例1.函數返回局部指針變量2.interface類型逃逸1.interface產生逃逸2.指向棧對象的指針不能在堆中3.閉包產生逃逸4.變量大小不確定及棧空間不足引發逃逸5.總結

1.什么是內存逃逸

在一段程序中,每一個函數都會有自己的內存區域分配自己的局部變量,返回值,這些內存會由編譯器在棧中進行分配,每一個函數會分配一個棧幀,在函數運行結束后銷毀,但是有些變量我們想在函數運行結束后仍然使用,就需要把這個變量分配在堆上,這種從棧上逃逸到堆上的現象叫做內存逃逸

2.什么是逃逸分析

雖然Go語言引入的Gc,GC機制會對堆上的對象進行管理,當某個對象不可達(沒有其他對象引用他),他將會被回收。雖然GC可以降低工作人員負擔,但是GC也會給程序帶來性能損耗,當堆內存上有大量的堆內存對象,就會給GC很大的壓力,雖然Go語言使用的是標記清除算法,并且在此基礎上使用了三色標記法和寫屏障技術,但是我們在堆上分配大量內存,仍然會對GC造成很大壓力,Go引入了逃逸分析,就是想減少堆內存的分配,可以在棧分配的內存盡量分配在棧上

3.小結

逃逸分析就是在程序編譯階段根據代碼中的數據流,對代碼中哪些變量需要在棧上分配,哪些需要在對象分配的靜態分析方法,堆和棧相比,堆適合分配不可預知大小的內存,但是付出代價是分配速度慢,容易產生碎片,棧分配十分快,棧分配只需要兩個指令Push和Release分配和釋放,而且堆分配需要先找一塊適合大小的內存塊分配,需要垃圾回收釋放,所以逃逸分析可以更好的做內存分配

Go語言的逃逸分析

src/cmd/compile/internal/gc/escape.go

pointerstostackobjectscannotbestoredintheheap:指向棧對象的指針不能存儲在堆中pointerstoastackobjectcannotoutlivethatobject:指向棧對象的指針不能超過該對象的存活期,指針不能在棧對象銷毀之后依然存活(例子:聲明的函數返回并銷毀了對象的棧幀,或者它在循環迭代中被重復用于邏輯上不同的變量)

既然逃逸分析是在編譯階段進行的,那我們就可以通過gobuild-gcflga-m-ml查看逃逸分析結果

4.逃逸分析案例

1.函數返回局部指針變量

funcAdd(x,yint)*int{

res:=0

res=x+y

returnres

funcmain(){

Add(1,2)

.\pointer.go:4:2:resescapestoheap:

.\pointer.go:4:2:flow:~r2=res:

.\pointer.go:4:2:fromres(address-of)at.\pointer.go:6:9

.\pointer.go:4:2:fromreturnres(return)at.\pointer.go:6:2

.\pointer.go:4:2:movedtoheap:res

函數返回局部變量是一個指針變量,函數Add執行結束,對應棧幀就會銷毀,但是引用返回到函數外部,如果我們外部解析地址,就會導致程序訪問非法內存,所以經過編輯器分析過后將其在堆上分配

2.interface類型逃逸

1.interface產生逃逸

funcmain(){

str:="荔枝"

fmt.Println(str)

E:\GoStudy\src\HighBase\Escapegobuild-gcflags=-m-m-l./pointer.go

.\pointer.go:20:13:strescapestoheap:

.\pointer.go:20:13:flow:{storagefor...argument}={storageforstr}:

.\pointer.go:20:13:fromstr(spill)at.\pointer.go:20:13

.\pointer.go:20:13:from...argument(slice-literal-element)at.\pointer.go:20:13

.\pointer.go:20:13:flow:{heap}={storagefor...argument}:

.\pointer.go:20:13:from...argument(spill)at.\pointer.go:20:13

.\pointer.go:20:13:fromfmt.Println(...argument...)(callparameter)at.\pointer.go:20:13

.\pointer.go:20:13:...argumentdoesnotescape

.\pointer.go:20:13:strescapestoheap

str是main的一個局部變量,傳給fmt.Printl()之后逃逸,因為fmt.Println()的入參是interface{}類型,如果參數為interface{},那么編譯期間就很難確定參數類型

2.指向棧對象的指針不能在堆中

我們把代碼改成這樣

funcmain(){

str:="蘇珊"

fmt.Println(str)

.\pointer.go:19:2:strescapestoheap:

.\pointer.go:19:2:flow:{storagefor...argument}=str:

.\pointer.go:19:2:fromstr(address-of)at.\pointer.go:20:14

.\pointer.go:19:2:fromstr(interface-converted)at.\pointer.go:20:14

.\pointer.go:19:2:from...argument(slice-literal-element)at.\pointer.go:20:13

.\pointer.go:19:2:flow:{heap}={storagefor...argument}:

.\pointer.go:19:2:from...argument(spill)at.\pointer.go:20:13

.\pointer.go:19:2:fromfmt.Println(...argument...)(callparameter)at.\pointer.go:20:13

.\pointer.go:19:2:movedtoheap:str

.\pointer.go:20:13:...argumentdoesnotescape

這次str也逃逸到堆上面了,在堆上面進行分配,因為入參是interface,變量str的地址被以實參的方式傳入fmt.Println被裝箱到一個interface{}

裝箱的形參變量要在堆上分配,但是還需要存儲一個棧上的地址,這和之前說的第一條不符,所以str也會分配到堆上

3.閉包產生逃逸

funcIncrease()func()int{

n:=0

returnfunc()int{

n++

returnn

funcmain(){

in:=Increase()

fmt.Println(in())//1

E:\GoStudy\src\HighBase\Escapegobuild-gcflags-m-m-l./pointer.go

.\pointer.go:27:2:Increasecapturingbyref:n(addr=falseassign=truewidth=8)

.\pointer.go:28:9:funcliteralescapestoheap:

.\pointer.go:28:9:flow:~r0={storageforfuncliteral}:

.\pointer.go:28:9:fromfuncliteral(spill)at.\pointer.go:28:9

.\pointer.go:28:9:fromreturnfuncliteral(return)at.\pointer.go:28:2

.\pointer.go:27:2:nescapestoheap:

.\pointer.go:27:2:flow:{storageforfuncliteral}=n:

.\pointer.go:27:2:fromn(capturedbyaclosure)at.\pointer.go:29:3

.\pointer.go:27:2:fromn(reference)at.\pointer.go:29:3

.\pointer.go:27:2:movedtoheap:n

.\pointer.go:28:9:funcliteralescapestoheap

.\pointer.go:36:16:in()escapestoheap:

.\pointer.go:36:16:flow:{storagefor...argument}={storageforin()}:

.\pointer.go:36:16:fromin()(spill)at.\pointer.go:36:16

.\pointer.go:36:16:from...argument(slice-literal-element)at.\pointer.go:36:13

.\pointer.go:36:16:flow:{heap}={storagefor...argument}:

.\pointer.go:36:16:from...argument(spill)at.\pointer.go:36:13

.\pointer.go:36:16:fromfmt.Println(...argument...)(callparameter)at.\pointer.go:36:13

.\pointer.go:36:13:...argumentdoesnotescape

.\pointer.go:36:16:in()escap

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論