淺談Golang內(nèi)存逃逸_第1頁(yè)
淺談Golang內(nèi)存逃逸_第2頁(yè)
淺談Golang內(nèi)存逃逸_第3頁(yè)
淺談Golang內(nèi)存逃逸_第4頁(yè)
淺談Golang內(nèi)存逃逸_第5頁(yè)
已閱讀5頁(yè),還剩2頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第淺談Golang內(nèi)存逃逸目錄1.什么是內(nèi)存逃逸2.什么是逃逸分析3.小結(jié)4.逃逸分析案例1.函數(shù)返回局部指針變量2.interface類型逃逸1.interface產(chǎn)生逃逸2.指向棧對(duì)象的指針不能在堆中3.閉包產(chǎn)生逃逸4.變量大小不確定及??臻g不足引發(fā)逃逸5.總結(jié)

1.什么是內(nèi)存逃逸

在一段程序中,每一個(gè)函數(shù)都會(huì)有自己的內(nèi)存區(qū)域分配自己的局部變量,返回值,這些內(nèi)存會(huì)由編譯器在棧中進(jìn)行分配,每一個(gè)函數(shù)會(huì)分配一個(gè)棧幀,在函數(shù)運(yùn)行結(jié)束后銷毀,但是有些變量我們想在函數(shù)運(yùn)行結(jié)束后仍然使用,就需要把這個(gè)變量分配在堆上,這種從棧上逃逸到堆上的現(xiàn)象叫做內(nèi)存逃逸

2.什么是逃逸分析

雖然Go語(yǔ)言引入的Gc,GC機(jī)制會(huì)對(duì)堆上的對(duì)象進(jìn)行管理,當(dāng)某個(gè)對(duì)象不可達(dá)(沒(méi)有其他對(duì)象引用他),他將會(huì)被回收。雖然GC可以降低工作人員負(fù)擔(dān),但是GC也會(huì)給程序帶來(lái)性能損耗,當(dāng)堆內(nèi)存上有大量的堆內(nèi)存對(duì)象,就會(huì)給GC很大的壓力,雖然Go語(yǔ)言使用的是標(biāo)記清除算法,并且在此基礎(chǔ)上使用了三色標(biāo)記法和寫屏障技術(shù),但是我們?cè)诙焉戏峙浯罅績(jī)?nèi)存,仍然會(huì)對(duì)GC造成很大壓力,Go引入了逃逸分析,就是想減少堆內(nèi)存的分配,可以在棧分配的內(nèi)存盡量分配在棧上

3.小結(jié)

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

Go語(yǔ)言的逃逸分析

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

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

既然逃逸分析是在編譯階段進(jìn)行的,那我們就可以通過(guò)gobuild-gcflga-m-ml查看逃逸分析結(jié)果

4.逃逸分析案例

1.函數(shù)返回局部指針變量

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

函數(shù)返回局部變量是一個(gè)指針變量,函數(shù)Add執(zhí)行結(jié)束,對(duì)應(yīng)棧幀就會(huì)銷毀,但是引用返回到函數(shù)外部,如果我們外部解析地址,就會(huì)導(dǎo)致程序訪問(wèn)非法內(nèi)存,所以經(jīng)過(guò)編輯器分析過(guò)后將其在堆上分配

2.interface類型逃逸

1.interface產(chǎn)生逃逸

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的一個(gè)局部變量,傳給fmt.Printl()之后逃逸,因?yàn)閒mt.Println()的入?yún)⑹莍nterface{}類型,如果參數(shù)為interface{},那么編譯期間就很難確定參數(shù)類型

2.指向棧對(duì)象的指針不能在堆中

我們把代碼改成這樣

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也逃逸到堆上面了,在堆上面進(jìn)行分配,因?yàn)槿雲(yún)⑹莍nterface,變量str的地址被以實(shí)參的方式傳入fmt.Println被裝箱到一個(gè)interface{}

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

3.閉包產(chǎn)生逃逸

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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論