原文地址:用 GODEBUG 看 GChtml
在計算機科學中,垃圾回收(GC)是一種自動管理內存的機制,垃圾回收器會去嘗試回收程序再也不使用的對象及其佔用的內存。而最先 John McCarthy 在 1959 年左右發明了垃圾回收,以簡化 Lisp 中的手動內存管理的機制(來自 wikipedia)。git
手動管理內存挺麻煩,管錯或者管漏內存也很糟糕,將會直接致使程序不穩定(持續泄露)甚至直接崩潰。github
硬要說會帶來什麼問題的話,也就數你們最關注的 Stop The World(STW),STW 代指在執行某個垃圾回收算法的某個階段時,須要將整個應用程序暫停去處理 GC 相關的工做事項。例如:golang
行爲 | 會不會 STW | 爲何 |
---|---|---|
標記開始 | 會 | 在開始標記時,準備根對象的掃描,會打開寫屏障(Write Barrier) 和 輔助GC(mutator assist),而回收器和應用程序是併發運行的,所以會暫停當前正在運行的全部 Goroutine。 |
併發標記中 | 不會 | 標記階段,主要目的是標記堆內存中仍在使用的值。 |
標記結束 | 會 | 在完成標記任務後,將從新掃描部分根對象,這時候會禁用寫屏障(Write Barrier)和輔助GC(mutator assist),而標記階段和應用程序是併發運行的,因此在標記階段可能會有新的對象產生,所以在從新掃描時須要進行 STW。 |
能夠經過 GOGC 變量設置初始垃圾收集器的目標百分比值,對比的規則爲當新分配的數值與上一次收集後剩餘的實時數值的比例達到設置的目標百分比時,就會觸發 GC,默認值爲 GOGC=100。若是將其設置爲 GOGC=off 能夠徹底禁用垃圾回收器,要不試試?算法
簡單來說就是,GOGC 的值設置的越大,GC 的頻率越低,但每次最終所觸發到 GC 的堆內存也會更大。c#
版本 | GC 算法 | STW 時間 |
---|---|---|
Go 1.0 | STW(強依賴 tcmalloc) | 百ms到秒級別 |
Go 1.3 | Mark STW, Sweep 並行 | 百ms級別 |
Go 1.5 | 三色標記法, 併發標記清除。同時運行時從 C 和少許彙編,改成 Go 和少許彙編實現 | 10-50ms級別 |
Go 1.6 | 1.5 中一些與併發 GC 不協調的地方更改,集中式的 GC 協調協程,改成狀態機實現 | 5ms級別 |
Go 1.7 | GC 時由 mark 棧收縮改成併發,span 對象分配機制由 freelist 改成 bitmap 模式,SSA引入 | ms級別 |
Go 1.8 | 混合寫屏障(hybrid write barrier), 消除 re-scanning stack | sub ms |
Go 1.12 | Mark Termination 流程優化 | sub ms, 但幾乎減小一半 |
注:資料來源於 @boya 在深圳 Gopher Meetup 的分享。併發
GODEBUG 變量能夠控制運行時內的調試變量,參數以逗號分隔,格式爲:name=val
。本文着重點在 GC 的觀察上,主要涉及 gctrace 參數,咱們經過設置 gctrace=1
後就能夠使得垃圾收集器向標準錯誤流發出 GC 運行信息。post
func main() { wg := sync.WaitGroup{} wg.Add(10) for i := 0; i < 10; i++ { go func(wg *sync.WaitGroup) { var counter int for i := 0; i < 1e10; i++ { counter++ } wg.Done() }(&wg) } wg.Wait() }
$ GODEBUG=gctrace=1 go run main.go gc 1 @0.032s 0%: 0.019+0.45+0.003 ms clock, 0.076+0.22/0.40/0.80+0.012 ms cpu, 4->4->0 MB, 5 MB goal, 4 P gc 2 @0.046s 0%: 0.004+0.40+0.008 ms clock, 0.017+0.32/0.25/0.81+0.034 ms cpu, 4->4->0 MB, 5 MB goal, 4 P gc 3 @0.063s 0%: 0.004+0.40+0.008 ms clock, 0.018+0.056/0.32/0.64+0.033 ms cpu, 4->4->0 MB, 5 MB goal, 4 P gc 4 @0.080s 0%: 0.004+0.45+0.016 ms clock, 0.018+0.15/0.34/0.77+0.065 ms cpu, 4->4->1 MB, 5 MB goal, 4 P gc 5 @0.095s 0%: 0.015+0.87+0.005 ms clock, 0.061+0.27/0.74/1.8+0.023 ms cpu, 4->4->1 MB, 5 MB goal, 4 P gc 6 @0.113s 0%: 0.014+0.69+0.002 ms clock, 0.056+0.23/0.48/1.4+0.011 ms cpu, 4->4->1 MB, 5 MB goal, 4 P gc 7 @0.140s 1%: 0.031+2.0+0.042 ms clock, 0.12+0.43/1.8/0.049+0.17 ms cpu, 4->4->1 MB, 5 MB goal, 4 P ...
gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # P
gc#
:GC 執行次數的編號,每次疊加。@#s
:自程序啓動後到當前的具體秒數。#%
:自程序啓動以來在GC中花費的時間百分比。#+...+#
:GC 的標記工做共使用的 CPU 時間佔總 CPU 時間的百分比。#->#-># MB
:分別表示 GC 啓動時, GC 結束時, GC 活動時的堆大小.#MB goal
:下一次觸發 GC 的內存佔用閾值。#P
:當前使用的處理器 P 的數量。gc 7 @0.140s 1%: 0.031+2.0+0.042 ms clock, 0.12+0.43/1.8/0.049+0.17 ms cpu, 4->4->1 MB, 5 MB goal, 4 P
0.031+2.0+0.042 ms clock:優化
0.12+0.43/1.8/0.049+0.17 ms cpu:spa
4->4->1 MB:
經過本章節咱們掌握了使用 GODEBUG 查看應用程序 GC 運行狀況的方法,只要用這種方法咱們就能夠觀測不一樣狀況下 GC 的狀況了,甚至能夠作出很是直觀的對比圖,你們不妨嘗試一下。