bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

go語言內存逃逸優化 go語言內存不斷升高

Go 語言內存管理(三):逃逸分析

Go 語言較之 C 語言一個很大的優勢就是自帶 GC 功能,可 GC 并不是沒有代價的。寫 C 語言的時候,在一個函數內聲明的變量,在函數退出后會自動釋放掉,因為這些變量分配在棧上。如果你期望變量的數據可以在函數退出后仍然能被訪問,就需要調用 malloc 方法在堆上申請內存,如果程序不再需要這塊內存了,再調用 free 方法釋放掉。Go 語言不需要你主動調用 malloc 來分配堆空間,編譯器會自動分析,找出需要 malloc 的變量,使用堆內存。編譯器的這個分析過程就叫做逃逸分析。

創新互聯公司是一家以成都網站建設公司、網頁設計、品牌設計、軟件運維、seo優化、小程序App開發等移動開發為一體互聯網公司。已累計為格柵板等眾行業中小客戶提供優質的互聯網建站和軟件開發服務。

所以你在一個函數中通過 dict := make(map[string]int) 創建一個 map 變量,其背后的數據是放在棧空間上還是堆空間上,是不一定的。這要看編譯器分析的結果。

可逃逸分析并不是百分百準確的,它有缺陷。有的時候你會發現有些變量其實在棧空間上分配完全沒問題的,但編譯后程序還是把這些數據放在了堆上。如果你了解 Go 語言編譯器逃逸分析的機制,在寫代碼的時候就可以有意識地繞開這些缺陷,使你的程序更高效。

Go 語言雖然在內存管理方面降低了編程門檻,即使你不了解堆棧也能正常開發,但如果你要在性能上較真的話,還是要掌握這些基礎知識。

這里不對堆內存和棧內存的區別做太多闡述。簡單來說就是, 棧分配廉價,堆分配昂貴。 棧空間會隨著一個函數的結束自動釋放,堆空間需要時間 GC 模塊不斷地跟蹤掃描回收。如果對這兩個概念有些迷糊,建議閱讀下面 2 個文章:

這里舉一個小例子,來對比下堆棧的差別:

stack 函數中的變量 i 在函數退出會自動釋放;而 heap 函數返回的是對變量 i 的引用,也就是說 heap() 退出后,表示變量 i 還要能被訪問,它會自動被分配到堆空間上。

他們編譯出來的代碼如下:

邏輯的復雜度不言而喻,從上面的匯編中可看到, heap() 函數調用了 runtime.newobject() 方法,它會調用 mallocgc 方法從 mcache 上申請內存,申請的內部邏輯前面文章已經講述過。堆內存分配不僅分配上邏輯比棧空間分配復雜,它最致命的是會帶來很大的管理成本,Go 語言要消耗很多的計算資源對其進行標記回收(也就是 GC 成本)。

Go 編輯器會自動幫我們找出需要進行動態分配的變量,它是在編譯時追蹤一個變量的生命周期,如果能確認一個數據只在函數空間內訪問,不會被外部使用,則使用棧空間,否則就要使用堆空間。

我們在 go build 編譯代碼時,可使用 -gcflags '-m' 參數來查看逃逸分析日志。

以上面的兩個函數為例,編譯的日志輸出是:

日志中的 i escapes to heap 表示該變量數據逃逸到了堆上。

需要使用堆空間,所以逃逸,這沒什么可爭議的。但編譯器有時會將 不需要 使用堆空間的變量,也逃逸掉。這里是容易出現性能問題的大坑。網上有很多相關文章,列舉了一些導致逃逸情況,其實總結起來就一句話:

多級間接賦值容易導致逃逸 。

這里的多級間接指的是,對某個引用類對象中的引用類成員進行賦值。Go 語言中的引用類數據類型有 func , interface , slice , map , chan , *Type(指針) 。

記住公式 Data.Field = Value ,如果 Data , Field 都是引用類的數據類型,則會導致 Value 逃逸。這里的等號 = 不單單只賦值,也表示參數傳遞。

根據公式,我們假設一個變量 data 是以下幾種類型,相應的可以得出結論:

下面給出一些實際的例子:

如果變量值是一個函數,函數的參數又是引用類型,則傳遞給它的參數都會逃逸。

上例中 te 的類型是 func(*int) ,屬于引用類型,參數 *int 也是引用類型,則調用 te(j) 形成了為 te 的參數(成員) *int 賦值的現象,即 te.i = j 會導致逃逸。代碼中其他幾種調用都沒有形成 多級間接賦值 情況。

同理,如果函數的參數類型是 slice , map 或 interface{} 都會導致參數逃逸。

匿名函數的調用也是一樣的,它本質上也是一個函數變量。有興趣的可以自己測試一下。

只要使用了 Interface 類型(不是 interafce{} ),那么賦值給它的變量一定會逃逸。因為 interfaceVariable.Method() 先是間接的定位到它的實際值,再調用實際值的同名方法,執行時實際值作為參數傳遞給方法。相當于 interfaceVariable.Method.this = realValue

向 channel 中發送數據,本質上就是為 channel 內部的成員賦值,就像給一個 slice 中的某一項賦值一樣。所以 chan *Type , chan map[Type]Type , chan []Type , chan interface{} 類型都會導致發送到 channel 中的數據逃逸。

這本來也是情理之中的,發送給 channel 的數據是要與其他函數分享的,為了保證發送過去的指針依然可用,只能使用堆分配。

可變參數如 func(arg ...string) 實際與 func(arg []string) 是一樣的,會增加一層訪問路徑。這也是 fmt.Sprintf 總是會使參數逃逸的原因。

例子非常多,這里不能一一列舉,我們只需要記住分析方法就好,即,2 級或更多級的訪問賦值會 容易 導致數據逃逸。這里加上 容易 二字是因為隨著語言的發展,相信這些問題會被慢慢解決,但現階段,這個可以作為我們分析逃逸現象的依據。

下面代碼中包含 2 種很常規的寫法,但他們卻有著很大的性能差距,建議自己想下為什么。

Benchmark 和 pprof 給出的結果:

熟悉堆棧概念可以讓我們更容易看透 Go 程序的性能問題,并進行優化。

多級間接賦值會導致 Go 編譯器出現不必要的逃逸,在一些情況下可能我們只需要修改一下數據結構就會使性能有大幅提升。這也是很多人不推薦在 Go 中使用指針的原因,因為它會增加一級訪問路徑,而 map , slice , interface{} 等類型是不可避免要用到的,為了減少不必要的逃逸,只能拿指針開刀了。

大多數情況下,性能優化都會為程序帶來一定的復雜度。建議實際項目中還是怎么方便怎么寫,功能完成后通過性能分析找到瓶頸所在,再對局部進行優化。

【golang】內存逃逸常見情況和避免方式

因為如果變量的內存發生逃逸,它的生命周期就是不可知的,其會被分配到堆上,而堆上分配內存不能像棧一樣會自動釋放,為了解放程序員雙手,專注于業務的實現,go實現了gc垃圾回收機制,但gc會影響程序運行性能,所以要盡量減少程序的gc操作。

1、在方法內把局部變量指針返回,被外部引用,其生命周期大于棧,則溢出。

2、發送指針或帶有指針的值到channel,因為編譯時候無法知道那個goroutine會在channel接受數據,編譯器無法知道什么時候釋放。

3、在一個切片上存儲指針或帶指針的值。比如[]*string,導致切片內容逃逸,其引用值一直在堆上。

4、因為切片的append導致超出容量,切片重新分配地址,切片背后的存儲基于運行時的數據進行擴充,就會在堆上分配。

5、在interface類型上調用方法,在Interface調用方法是動態調度的,只有在運行時才知道。

1、go語言的接口類型方法調用是動態,因此不能在編譯階段確定,所有類型結構轉換成接口的過程會涉及到內存逃逸發生,在頻次訪問較高的函數盡量調用接口。

2、不要盲目使用變量指針作為參數,雖然減少了復制,但變量逃逸的開銷更大。

3、預先設定好slice長度,避免頻繁超出容量,重新分配。

什么是逃逸分析?

在C語言中,可以使用malloc和free手動在堆上分配和回收內存。Go語言中,堆內存是通過垃圾回收機制自動管理的,無需開發者指定。那么,Go編譯器怎么知道某個變量需要分配在棧上,還是堆上呢?編譯器決定內存分配位置的方式,就稱之為逃逸分析(escape analysis)。逃逸分析由編譯器完成,作用于編譯階段。

面試問題總結(一)Golang

使用go語言的好處: go語言的設計是務實的, go在針對并發上進行了優化, 并且支持大規模高并發, 又由于單一的碼格式, 相比于其他語言更具有可讀性, 在垃圾回收上比java和Python更有效, 因為他是和程序同時執行的.

1. 進程, 線程, 協程的區別, 協程的優勢

2. 講一下GMP模型(重點)

3. Go的GC, 混合寫屏障(重點)

4. go的Slice和數組的區別, slice的擴容原理(重點)

5. 講一下channel,實現原理(重點)

6. 講一下Go的Map的實現原理, 是否線程安全, 如何實現安全(重點)

7. new 和 make 的區別

8. 說一下內存逃逸

9. 函數傳指針和傳值有什么區別

10. goroutine之間的通信方式

11. 測試是怎么做的(單元測試, 壓力測試)

12. 堆和棧的區別

網站名稱:go語言內存逃逸優化 go語言內存不斷升高
URL分享:http://vcdvsql.cn/article24/hejice.html

成都網站建設公司_創新互聯,為您提供建站公司品牌網站建設外貿網站建設標簽優化商城網站面包屑導航

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

成都做網站