Go 內存分配管理

一、問題引入

現象:在實際工作項目中,golang項目經常內存報警,現象為在流量增大,或傳入很大文件的情況下算法worker內存降低到一定限度之後(100Mb左右),過一段時間才能內存才能自動恢復。

  • Go內存管理機制,Go自己本身會管理內存,釋放的內存不會立即歸還給操作系統,在一定時間之後才會歸還給操作系統,過早的釋放內存歸還給操作系統會降低性能。
  • 內存泄漏,Go調用CGO算法模塊時,導致瞭內存泄漏
  • 進程占用的內存過大導致進程掛掉,並釋放瞭內存,supervisor自動重啟瞭進程,內存曲線恢復正常

二、幾個基本概念

1.RSS,VSS解釋

對於RAM內存的使用,實際是os kernel來控制的。

  • RSS(Resident Set Size)表示該進程分配的占用RAM的內存大小,不包括交互分區內存,包括共享庫占用的內存,棧內存,堆內存
  • VSZ(Virtual Memory Size)表示該進程分配的虛擬內存大小,包括進程可以訪問的所有內存,包括交換分區,共享內存

舉例說明RSS,VSS:

如果一個進程,程序的大小有 500K,鏈接的共享庫大小有 2500K,堆棧內存共有 200K,其中 100K 進入瞭交換分區。進程實際加載瞭共享庫中的 1000K 的內容,以及自己程序的中的 400K 的內容。請問 RSS 和 VSZ 應是多少?RSS: 400K + 1000K + 100K = 1500K VSZ: 500K + 2500K + 200K = 3200K

三、Go內存管理機制

1.Go runtime內存延遲歸還

Go是一種高級語言,自帶GC。內存的分配和回收都是自動的被垃圾回收器所執行,當某個對象內存變成不可達狀態時(unreachable)。垃圾回收器則將其回收。

Go中空閑的內存,並不意味著立即歸還給操作系統。空閑的內存可以被重新利用。因此Go語言中,即使某些對象被釋放瞭,操作系統的內存使用並沒有下降。這是因為Go的內存管理器,將其標為free,並可以重新利用。

Go runtime不會立刻歸還內存給操作系統,內存在大約5分鐘左右沒有被使用時,才會歸還給操作系統。

例如:在處理Http請求時讀取HttpBodyBytes.Buffer中,處理完HttpBody的內容之後,並不會立刻釋放內存給OS,而是將這些內存對下一個Http請求進行內存的復用。

編寫如下:簡單的http服務,並使用ab進行壓測可以驗證Go gc的延遲歸還內存給操作系統:

func main() {  
    http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {  
        fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))  
    })  

    http.ListenAndServe(":8010", nil)  

    fmt.Println("hello")  
}  

初始:

$ ps -p 563 -v  
  PID TTY      STAT   TIME  MAJFL   TRS   DRS   RSS %MEM COMMAND  
  563 pts/19   SNl    0:27      0  2100 359203  3480  0.1 ./http  

壓測後:

ab -n 1000000 -c 1000 http://10.104.7.46:8010/bar
$ ps -p 563 -v  
  PID TTY      STAT   TIME  MAJFL   TRS   DRS   RSS %MEM COMMAND  
  563 pts/19   SNl    0:27      0  2100 359203 12908  0.1 ./http  

 5min後:

$ ps -p 563 -v  
  PID TTY      STAT   TIME  MAJFL   TRS   DRS   RSS %MEM COMMAND  
  563 pts/19   SNl    0:27      0  2100 359203 4816  0.0 ./http  

可以看到RSS由3480到12908在到4816,結合free -m可以看到內存一樣的變化,因此驗證瞭golang的內存管理的延遲歸還特性。

2.強制歸還內存

debug.FreeOSMemory()

該函數強制盡可能多的將內存歸還給操作系統。不推薦手動調用釋放內存,

FreeOSMemory

的操作在後臺進程runtime來負責執行,定期歸還內存給操作系統。

到此這篇關於Go 內存分配管理的文章就介紹到這瞭,更多相關Go 內存管理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: