golang 內(nèi)存監(jiān)控

最近的一個golang項(xiàng)目上生產(chǎn)后戒幔,發(fā)現(xiàn)RES內(nèi)存占用一直在輕微上漲:三天時間從一開始的40M,上漲到了60M左右派诬。之前對golang的內(nèi)存管理和垃圾回收機(jī)制一直不是很清晰,于是花些時間去把這個問題搞清楚吝羞。

1) VSZ,RSS,TTY,STAT, VIRT,RES,SHR,DATA的含義

我們需要關(guān)注的主要是RES內(nèi)存

o: VIRT -- Virtual Image (kb)
      The  total  amount  of  virtual  memory  used  by the task.  It
      includes all code, data and shared libraries  plus  pages  that
      have  been  swapped out and pages that have been mapped but not
      used.
 p: SWAP  --  Swapped size (kb)
      Memory that is not resident but is present in a task.  This  is
      memory  that  has been swapped out but could include additional
      non-resident memory.  This column is calculated by  subtracting
      physical memory from virtual memory.
  q: RES  --  Resident size (kb)
      The non-swapped physical memory a task has used.
  r: CODE  --  Code size (kb)
      The  amount  of virtual memory devoted to executable code, also
      known as the 'text resident set' size or TRS.
  s: DATA  --  Data+Stack size (kb)
      The amount of virtual memory devoted to other  than  executable
      code, also known as the 'data resident set' size or DRS.
  t: SHR  --  Shared Mem size (kb)
      The amount of shared memory used by a task.  It simply reflects
      memory that could be potentially shared with other processes.

VIRT:virtual memory usage 虛擬內(nèi)存
1、進(jìn)程“需要的”虛擬內(nèi)存大小内颗,包括進(jìn)程使用的庫钧排、代碼、數(shù)據(jù)等等均澳。
2恨溜、假如進(jìn)程申請100m的內(nèi)存,但實(shí)際只使用了10m找前,那么它會增長100m糟袁,而不是實(shí)際的使用量

SHR:shared memory 共享內(nèi)存
1、除了自身進(jìn)程的共享內(nèi)存躺盛,也包括其他進(jìn)程的共享內(nèi)存
2、雖然進(jìn)程只使用了幾個共享庫的函數(shù),但它包含了整個共享庫的大小
3牙勘、計算某個進(jìn)程所占的物理內(nèi)存大小公式:RES – SHR
4骇钦、swap out后,它將會降下來

RES:resident memory usage 常駐內(nèi)存
1界斜、進(jìn)程當(dāng)前使用的內(nèi)存大小仿耽,但不包括swap out
2、包含其他進(jìn)程的共享
3各薇、如果申請100m的內(nèi)存项贺,實(shí)際使用10m,它只增長10m峭判,與VIRT相反
4开缎、關(guān)于庫占用內(nèi)存的情況,它只統(tǒng)計加載的庫文件所占內(nèi)存大小

DATA
1朝抖、數(shù)據(jù)占用的內(nèi)存啥箭。如果top沒有顯示,按f鍵可以顯示出來治宣。
2急侥、真正的該程序要求的數(shù)據(jù)空間,是真正在運(yùn)行中要使用的侮邀。

2) golang監(jiān)控內(nèi)存的方式

1 利用GCVIS進(jìn)行可視化監(jiān)控

原理可參考:http://holys.im/2016/07/01/monitor-golang-gc/
這是最簡單的方式坏怪,好處是不用修改程序代碼。

1)安裝

go get https://github.com/davecheney/gcvis 或者git clone https://github.com/davecheney/gcvis 到本地自行安裝

2)啟動監(jiān)控(要運(yùn)行的文件是/path/to/binary)

有兩種方式
1绊茧、 直接運(yùn)行

./gcvis /path/to/binary

2铝宵、 管道重定向方式(standard error)

GODEBUG=gctrace=1  /path/to/binary  |& ./gcvis

我這里運(yùn)行的是

env GOMAXPROCS=4 ./gcvis -o=false -p 12345  -i 10.107.101.1 /path/to/binary

可訪問頁面http://10.107.101.1:12345 獲取可視化結(jié)果。

2 利用pprof進(jìn)行監(jiān)控

具體可參考:https://studygolang.com/articles/9940
go中有pprof包來做代碼的性能監(jiān)控主要涉及兩個pkg:

#web服務(wù)器:
import (
    "net/http"
    _ "net/http/pprof"
)

#一般應(yīng)用程序(實(shí)際應(yīng)用無web交互)
import (
    "net/http"
    _ "runtime/pprof"
)

其實(shí)net/http/pprof中只是使用runtime/pprof包來進(jìn)行封裝了一下,并在http端口上暴露出來

1)修改代碼

需要對原來的程序代碼進(jìn)行修改

web 服務(wù)器

如果你的go程序是用http包啟動的web服務(wù)器鹏秋,可以選擇net/http/pprof尊蚁。
只需要引入包_"net/http/pprof",然后就可以在瀏覽器中使用 http://localhost:port/debug/pprof/
直接看到當(dāng)前web服務(wù)的狀態(tài)侣夷,包括CPU占用情況和內(nèi)存使用情況等横朋。

服務(wù)進(jìn)程

如果你的go程序不是web服務(wù)器,而是一個服務(wù)進(jìn)程百拓,也可以選擇使用net/http/pprof包琴锭,同樣引入包net/http/pprof,然后在開啟另外一個goroutine來開啟端口監(jiān)聽衙传。

go func() {
        http.ListenAndServe("localhost:6060", nil)
}()

應(yīng)用程序

如果你的go程序只是一個應(yīng)用程序决帖,比如計算fabonacci數(shù)列,那么你就不能使用net/http/pprof包了蓖捶,你就需要使用到runtime/pprof地回。
具體做法就是用到pprof.StartCPUProfile和pprof.StopCPUProfile。
比如下面的例子:

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func main() {
    flag.Parse()
    if *cpuprofile != "" {
        f, err := os.Create(*cpuprofile)
        if err != nil {
            log.Fatal(err)
        }
        pprof.StartCPUProfile(f)
        defer pprof.StopCPUProfile()
    }

運(yùn)行程序的時候加一個--cpuprofile參數(shù)腺阳,比如 fabonacci --cpuprofile=fabonacci.prof
這樣程序運(yùn)行的時候的cpu信息就會記錄到XXX.prof中了落君。

2)查看監(jiān)控數(shù)據(jù)

兩種方式:
1 WEB上直接查看,瀏覽器直接訪問:http://XXX:6060/debug/pprof
2 通過 go tool pprof 查看
具體的數(shù)據(jù)字段含義參考
https://blog.csdn.net/m0_38132420/article/details/71699815
https://studygolang.com/articles/9940

3) FreeOSMemory()

折騰和很久亭引,發(fā)現(xiàn)兩種方式監(jiān)控到的內(nèi)存都比較穩(wěn)定绎速。但是TOP命令查看RES還是一直在增長。
查了很久的資料:
https://groups.google.com/forum/#!topic/Golang-Nuts/kuS4kLCwkbE
https://stackoverflow.com/questions/37382600/cannot-free-memory-once-occupied-by-bytes-buffer
https://golang.org/pkg/runtime/debug/#FreeOSMemory

最后發(fā)現(xiàn)焙蚓,golang的內(nèi)存即使被gc回收了纹冤,也不會立刻歸還給OS的,除非你手動調(diào)用FreeOSMemory()
這也是RES內(nèi)存一起比預(yù)期中高的原因

Some things to clear. Go is a garbage collected language, which means that memory allocated and used by variables is automatically freed by the garbage collector when those variables become unreachable (if you have another pointer to the variable, that still counts as "reachable").
Freed memory does not mean it is returned to the OS. Freed memory means the memory can be reclaimed, reused for another variable if there is a need. So from the operating system you won't see memory decreasing right away just because some variable became unreachable and the garbage collector detected this and freed memory used by it.
The Go runtime will however return memory to the OS if it is not used for some time (which is usually around 5 minutes). If the memory usage increases during this period (and optionally shrinks again), the memory will most likely not be returned to the OS

FreeOSMemory forces a garbage collection followed by an attempt to return as much memory to the operating system as possible. (Even if this is not called, the runtime gradually returns memory to the operating system in a background task.)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末购公,一起剝皮案震驚了整個濱河市萌京,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宏浩,老刑警劉巖知残,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異比庄,居然都是意外死亡求妹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門佳窑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來制恍,“玉大人,你說我怎么就攤上這事神凑【簧瘢” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鹃唯。 經(jīng)常有香客問我爱榕,道長,這世上最難降的妖魔是什么俯渤? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任呆细,我火速辦了婚禮,結(jié)果婚禮上八匠,老公的妹妹穿的比我還像新娘。我一直安慰自己趴酣,他們只是感情好梨树,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著岖寞,像睡著了一般抡四。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仗谆,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天指巡,我揣著相機(jī)與錄音,去河邊找鬼隶垮。 笑死藻雪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的狸吞。 我是一名探鬼主播勉耀,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蹋偏!你這毒婦竟也來了便斥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤威始,失蹤者是張志新(化名)和其女友劉穎枢纠,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體黎棠,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晋渺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了葫掉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片些举。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖俭厚,靈堂內(nèi)的尸體忽然破棺而出户魏,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布叼丑,位于F島的核電站关翎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鸠信。R本人自食惡果不足惜纵寝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望星立。 院中可真熱鬧爽茴,春花似錦、人聲如沸绰垂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劲装。三九已至胧沫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間占业,已是汗流浹背绒怨。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谦疾,地道東北人南蹂。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像餐蔬,于是被迫代替她去往敵國和親碎紊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容