Go 內(nèi)存分配管理
一、問題引入
現(xiàn)象:在實際工作項目中,golang項目經(jīng)常內(nèi)存報警,現(xiàn)象為在流量增大,或傳入很大文件的情況下算法worker內(nèi)存降低到一定限度之后(100Mb左右),過一段時間才能內(nèi)存才能自動恢復(fù)。

- Go內(nèi)存管理機(jī)制,Go自己本身會管理內(nèi)存,釋放的內(nèi)存不會立即歸還給操作系統(tǒng),在一定時間之后才會歸還給操作系統(tǒng),過早的釋放內(nèi)存歸還給操作系統(tǒng)會降低性能。
- 內(nèi)存泄漏,Go調(diào)用CGO算法模塊時,導(dǎo)致了內(nèi)存泄漏
- 進(jìn)程占用的內(nèi)存過大導(dǎo)致進(jìn)程掛掉,并釋放了內(nèi)存,
supervisor自動重啟了進(jìn)程,內(nèi)存曲線恢復(fù)正常
二、幾個基本概念
1.RSS,VSS解釋
對于RAM內(nèi)存的使用,實際是os kernel來控制的。
RSS(Resident Set Size)表示該進(jìn)程分配的占用RAM的內(nèi)存大小,不包括交互分區(qū)內(nèi)存,包括共享庫占用的內(nèi)存,棧內(nèi)存,堆內(nèi)存VSZ(Virtual Memory Size)表示該進(jìn)程分配的虛擬內(nèi)存大小,包括進(jìn)程可以訪問的所有內(nèi)存,包括交換分區(qū),共享內(nèi)存
舉例說明RSS,VSS:
如果一個進(jìn)程,程序的大小有 500K,鏈接的共享庫大小有 2500K,堆棧內(nèi)存共有 200K,其中 100K 進(jìn)入了交換分區(qū)。進(jìn)程實際加載了共享庫中的 1000K 的內(nèi)容,以及自己程序的中的 400K 的內(nèi)容。請問 RSS 和 VSZ 應(yīng)是多少?RSS: 400K + 1000K + 100K = 1500K VSZ: 500K + 2500K + 200K = 3200K
三、Go內(nèi)存管理機(jī)制
1.Go runtime內(nèi)存延遲歸還
Go是一種高級語言,自帶GC。內(nèi)存的分配和回收都是自動的被垃圾回收器所執(zhí)行,當(dāng)某個對象內(nèi)存變成不可達(dá)狀態(tài)時(unreachable)。垃圾回收器則將其回收。
Go中空閑的內(nèi)存,并不意味著立即歸還給操作系統(tǒng)??臻e的內(nèi)存可以被重新利用。因此Go語言中,即使某些對象被釋放了,操作系統(tǒng)的內(nèi)存使用并沒有下降。這是因為Go的內(nèi)存管理器,將其標(biāo)為free,并可以重新利用。
Go runtime不會立刻歸還內(nèi)存給操作系統(tǒng),內(nèi)存在大約5分鐘左右沒有被使用時,才會歸還給操作系統(tǒng)。
例如:在處理Http請求時讀取HttpBody到Bytes.Buffer中,處理完HttpBody的內(nèi)容之后,并不會立刻釋放內(nèi)存給OS,而是將這些內(nèi)存對下一個Http請求進(jìn)行內(nèi)存的復(fù)用。
編寫如下:簡單的http服務(wù),并使用ab進(jìn)行壓測可以驗證Go gc的延遲歸還內(nèi)存給操作系統(tǒng):
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,結(jié)合free -m可以看到內(nèi)存一樣的變化,因此驗證了golang的內(nèi)存管理的延遲歸還特性。
2.強(qiáng)制歸還內(nèi)存
debug.FreeOSMemory()
該函數(shù)強(qiáng)制盡可能多的將內(nèi)存歸還給操作系統(tǒng)。不推薦手動調(diào)用釋放內(nèi)存,
FreeOSMemory
的操作在后臺進(jìn)程runtime來負(fù)責(zé)執(zhí)行,定期歸還內(nèi)存給操作系統(tǒng)。
到此這篇關(guān)于Go 內(nèi)存分配管理的文章就介紹到這了,更多相關(guān)Go 內(nèi)存管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang中文字符串截取函數(shù)實現(xiàn)原理
在golang中可以通過切片截取一個數(shù)組或字符串,但是當(dāng)截取的字符串是中文時,可能會出現(xiàn)問題,下面我們來自定義個函數(shù)解決Golang中文字符串截取問題2018-03-03
詳解Golang中Context的三個常見應(yīng)用場景
Golang?context主要用于定義超時取消,取消后續(xù)操作,在不同操作中傳遞值。本文通過簡單易懂的示例進(jìn)行說明,感興趣的可以了解一下2022-12-12
MacOS下本地golang環(huán)境搭建詳細(xì)教程
這篇文章主要介紹了MacOS下本地golang環(huán)境搭建詳細(xì)教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09

