1 先翻譯一下runtime 文檔中症歇,關(guān)于gc的內(nèi)容(里面涉及GC日志格式)
···
原文: https://golang.org/pkg/runtime/
翻譯參考: https://colobu.com/2016/07/04/dive-into-go-11/#pprof
···
allocfreetrace: 設(shè)置 allocfreetrace=1 會監(jiān)控每次分配郎笆,但因每次分配和釋放的棧信息(stack trace)
cgocheck: 設(shè)置 cgocheck=0 禁用所有cgo檢查將Go指針傳遞給非Go代碼是否正確。
cgocheck=1 (缺省值) 輕量級檢查忘晤。cgocheck=2 重量級檢查宛蚓。
efence: 設(shè)置 efence=1 導(dǎo)致分配器 allocator將每個對象分配在一個唯一的頁page上,地址不重用设塔。
gccheckmark: 設(shè)置 gccheckmark=1 允許垃圾回收器執(zhí)行并發(fā)mark階段的校驗凄吏。會導(dǎo)致Stop The World。
gcpacertrace: 設(shè)置 gcpacertrace=1 會讓來幾回收器打印出concurrent pacer的內(nèi)部狀態(tài)。
gcshrinkstackoff: 設(shè)置 gcshrinkstackoff=1 則禁止將 goroutines 的椇鄹郑縮小為更小棧图柏。
gcstackbarrieroff: 設(shè)置 gcstackbarrieroff=1 禁用stack barriers,會影響垃圾回收器的重復(fù)搜索棧的功能盖喷。
gcstackbarrierall: 設(shè)置 gcstackbarrierall=1 會為每個棧幀安裝一 stack barriers爆办。
gcstoptheworld: 設(shè)置 gcstoptheworld=1 則禁用并發(fā)垃圾回收,每次回收都會觸發(fā)STW。設(shè)置gcstoptheworld=2則禁用垃圾回收后的concurrent sweeping课梳。
gctrace: 設(shè)置 gctrace=1導(dǎo)致每次垃圾回收器觸發(fā)一行日志距辆,包含內(nèi)存回收的概要信息和暫停的時間。設(shè)置gctrace=2起同樣的效果暮刃,but also repeats each collection跨算。格式如下:
gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # P
where the fields are as follows:
gc # GC id,每次GC加一
@#s 程序啟動后的時間,單位秒
#% 程序啟動后GC所用的時間比
#+...+# 此次GC所用的wall-clock/CPU時間
#->#-># MB GC開始時的堆大小, GC結(jié)束時的堆大小, 活著的(live)堆大小
# MB goal 總的堆大小
# P CPU使用數(shù)
垃圾回收分為下面的幾個階段:stop-the-world (STW) sweep termination, concurrent
mark and scan, and STW mark termination椭懊。 mark/scan的CPU時間又分為 assist time (GC performed in
line with allocation), background GC time, and idle GC time诸蚕。
垃圾回收的四個階段:
Sweep Termination: 對未清掃的span進(jìn)行清掃, 只有上一輪的GC的清掃工作完成才可以開始新一輪的GC
Mark: 掃描所有根對象, 和根對象可以到達(dá)的所有對象, 標(biāo)記它們不被回收
Mark Termination: 完成標(biāo)記工作, 重新掃描部分根對象(要求STW)
Sweep: 按標(biāo)記結(jié)果清掃span
如果日志后以"(forced)"結(jié)尾,則GC通過runtime.GC()調(diào)用執(zhí)行,此時所有的階段都是STW.
memprofilerate: 設(shè)置 memprofilerate=X 會更新runtime.MemProfileRate的值氧猬。0則禁用這個profie背犯。
invalidptr: 默認(rèn)設(shè)為invalidptr=1, 如果指針被賦予一個無效值,會引起程序的崩潰,設(shè)置該值為0盅抚,會停止該檢查漠魏,
0只能臨時用于查找bug,真正的解決方法是不要把整數(shù)類型的值存在指針變量里面妄均。
sbrk: 設(shè)置 sbrk=1 會使用實驗性的實現(xiàn)替換memory allocator 和 garbage collector柱锹。
scavenge: scavenge=1 允許heap scavenger的debug模式。
scheddetail: 設(shè)置 schedtrace=X 和 scheddetail=1 會導(dǎo)致goroutine調(diào)度器每個X毫秒輸出多行調(diào)度信息丰包。
schedtrace: 設(shè)置 schedtrace=X導(dǎo)致調(diào)度器每個X秒輸出一行調(diào)度器的概要信息禁熏。
2 GC 觸發(fā)時機(jī)
gcTriggerHeap: 當(dāng)前分配的內(nèi)存達(dá)到一定值就觸發(fā)GC
gcTriggerTime: 當(dāng)一定時間沒有執(zhí)行過GC就觸發(fā)GC
gcTriggerCycle: 要求啟動新一輪的GC, 已啟動則跳過, 手動觸發(fā)GC的runtime.GC()會使用這個條件
3 gc 具體的過程
3.1 根對象
在GC的標(biāo)記階段首先需要標(biāo)記的就是"根對象", 從根對象開始可到達(dá)的所有對象都會被認(rèn)為是存活的.
根對象包含了全局變量, 各個G的棧上的變量等, GC會先掃描根對象然后再掃描根對象可到達(dá)的所有對象.
3.2 三色標(biāo)記過程
之前自己整理的 http://www.reibang.com/p/ebf03d9605d0
4 gc 優(yōu)化案例
4.1 減少分配對象數(shù)量(這樣就減少了掃描時間)
鏈接:https://www.zhihu.com/question/21615032/answer/18781477
4.2 一個檢測G 長時間占用CPU時間片,導(dǎo)致GC hang住的排查工具
https://github.com/zhanglvmeng/go-tool-trace-greediest-goroutines
4.3 【已驗證】io.copybuffer 沒傳buffer進(jìn)去邑彪,底層自動創(chuàng)建了多個buffer對象瞧毙,造成內(nèi)存泄漏,頻繁gc寄症。
https://my.oschina.net/u/2950272/blog/1788299
4.4 使用array 替代 map, 減少掃描時間
https://studygolang.com/articles/1720
4.5 多個不同維度的分析
http://guileen.github.io/2016/06/15/how-did-i-optimize-golang-gc/
4.6 減少GC的一些思路
http://www.philo.top/2015/05/29/golangProfilingAndGC2/
4.7 GC排查的步驟
4.8 string 以及[]byte 的GC問題
https://www.520mwx.com/view/35045
5 gc 查看工具
gcvis https://github.com/davecheney/gcvis
參考自 https://colobu.com/2016/07/04/dive-into-go-11/#pprof
6 GC 監(jiān)控
對于線上GC的監(jiān)控升筏,基本上讀取runtime.MemStats結(jié)構(gòu)中的內(nèi)容,然后存儲到時序數(shù)據(jù)庫中。具體有如下兩種獲取方式:
// 方式1
memStats := &runtime.MemStats{}
runtime.ReadMemStats(memStats)
// 方式2 json格式
expvar.Get("memstats").String()
7 scavenger
到目前為止,gctrace給出的最有用的信息就是 the heap scavenger的輸出.
scvg143: inuse: 8, idle: 104, sys: 113, released: 104, consumed: 8 (MB)
scvg143 表示第143次輸出戚扳。其他字段黄刚,見下圖。
圖片來源于https://colobu.com/2016/07/04/dive-into-go-11/#pprof
scavenger 的工作就是周期性地打掃h(yuǎn)eap中無用的操作系統(tǒng)內(nèi)存分頁胯舷, 它會向操作系統(tǒng)發(fā)出建義王带,請操作系統(tǒng)回收無用內(nèi)存頁埂软,
當(dāng)然并不能強(qiáng)迫操作系統(tǒng)立刻就去做回收處理享言,操作系統(tǒng)可以忽略此建義峻凫,或是延遲回收,比如直到可分配的空閑內(nèi)存不夠的時候览露。
scavenger輸出的信息是我們了解go程序虛擬內(nèi)存空間
使用情況的最好方式荧琼, 當(dāng)然你也可以通過其它工具,如free, top來獲到這些信息差牛,
不過你應(yīng)用信任scavenger.
8 參考文獻(xiàn)
非常詳細(xì)的文章https://yq.aliyun.com/blog/573819
gc 線上監(jiān)控: http://kuring.me/post/golang-gc/
scavenger: https://studygolang.com/articles/6346