Go 內(nèi)存管理

go 語言實(shí)際內(nèi)存、虛擬內(nèi)存怎么分配,延遲歸還是什么機(jī)制?本文結(jié)合監(jiān)控對(duì)內(nèi)存管理進(jìn)行了觀測(cè)。
“深入學(xué)習(xí)golang對(duì)于內(nèi)存的管理機(jī)制
問題引入
現(xiàn)象:在實(shí)際工作項(xiàng)目中,golang項(xiàng)目經(jīng)常內(nèi)存報(bào)警,現(xiàn)象為在流量增大,或傳入很大文件的情況下算法worker內(nèi)存降低到一定限度之后(100Mb左右),過一段時(shí)間才能內(nèi)存才能自動(dòng)恢復(fù)。

Go內(nèi)存管理機(jī)制,Go自己本身會(huì)管理內(nèi)存,釋放的內(nèi)存不會(huì)立即歸還給操作系統(tǒng),在一定時(shí)間之后才會(huì)歸還給操作系統(tǒng),過早的釋放內(nèi)存歸還給操作系統(tǒng)會(huì)降低性能。
內(nèi)存泄漏,Go調(diào)用CGO算法模塊時(shí),導(dǎo)致了內(nèi)存泄漏
進(jìn)程占用的內(nèi)存過大導(dǎo)致進(jìn)程掛掉,并釋放了內(nèi)存,supervisor自動(dòng)重啟了進(jìn)程,內(nèi)存曲線恢復(fù)正常
幾個(gè)基本概念
RSS,VSS解釋
對(duì)于RAM內(nèi)存的使用,實(shí)際是os kernel來控制的。
RSS(Resident Set Size)表示該進(jìn)程分配的占用RAM的內(nèi)存大小,不包括交互分區(qū)內(nèi)存,包括共享庫(kù)占用的內(nèi)存,棧內(nèi)存,堆內(nèi)存
VSZ(Virtual Memory Size)表示該進(jìn)程分配的虛擬內(nèi)存大小,包括進(jìn)程可以訪問的所有內(nèi)存,包括交換分區(qū),共享內(nèi)存
舉例說明RSS,VSS:
如果一個(gè)進(jìn)程,程序的大小有 500K,鏈接的共享庫(kù)大小有 2500K,堆棧內(nèi)存共有 200K,其中 100K 進(jìn)入了交換分區(qū)。進(jìn)程實(shí)際加載了共享庫(kù)中的 1000K 的內(nèi)容,以及自己程序的中的 400K 的內(nèi)容。請(qǐng)問 RSS 和 VSZ 應(yīng)是多少?RSS: 400K + 1000K + 100K = 1500K VSZ: 500K + 2500K + 200K = 3200K
Go內(nèi)存管理機(jī)制
Go runtime內(nèi)存延遲歸還
Go是一種高級(jí)語言,自帶GC。內(nèi)存的分配和回收都是自動(dòng)的被垃圾回收器所執(zhí)行,當(dāng)某個(gè)對(duì)象內(nèi)存變成不可達(dá)狀態(tài)時(shí)(unreachable)。垃圾回收器則將其回收。
Go中空閑的內(nèi)存,并不意味著立即歸還給操作系統(tǒng)。空閑的內(nèi)存可以被重新利用。因此Go語言中,即使某些對(duì)象被釋放了,操作系統(tǒng)的內(nèi)存使用并沒有下降。這是因?yàn)镚o的內(nèi)存管理器,將其標(biāo)為free,并可以重新利用。
Go runtime不會(huì)立刻歸還內(nèi)存給操作系統(tǒng),內(nèi)存在大約5分鐘左右沒有被使用時(shí),才會(huì)歸還給操作系統(tǒng)。
例如:在處理Http請(qǐng)求時(shí)讀取HttpBody到Bytes.Buffer中,處理完HttpBody的內(nèi)容之后,并不會(huì)立刻釋放內(nèi)存給OS,而是將這些內(nèi)存對(duì)下一個(gè)Http請(qǐng)求進(jìn)行內(nèi)存的復(fù)用。
編寫如下:簡(jiǎn)單的http服務(wù),并使用ab進(jìn)行壓測(cè)可以驗(yà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")??
}??
1. ?初始
$?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??
2. ?壓測(cè)后: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??
3. ?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)存一樣的變化,因此驗(yàn)證了golang的內(nèi)存管理的延遲歸還特性。
強(qiáng)制歸還內(nèi)存
debug.FreeOSMemory() 該函數(shù)強(qiáng)制盡可能多的將內(nèi)存歸還給操作系統(tǒng)。不推薦手動(dòng)調(diào)用釋放內(nèi)存,FreeOSMemory的操作在后臺(tái)進(jìn)程runtime來負(fù)責(zé)執(zhí)行,定期歸還內(nèi)存給操作系統(tǒng)。
轉(zhuǎn)自:dreamgoing.github.io
文章轉(zhuǎn)載:Go開發(fā)大全
(版權(quán)歸原作者所有,侵刪)

點(diǎn)擊下方“閱讀原文”查看更多
