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請求時讀取HttpBody
到Bytes.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!
推薦閱讀:
- Go語言HTTPServer開發的六種方式小結
- golang開發安裝go-torch火焰圖操作步驟
- golang 實現Location跳轉方式
- go web 預防跨站腳本的實現方式
- go語言日志實現詳解(打印日志、日志寫入文件和日志切割)