內存泄露,是從操做系統的角度上來闡述的,形象的比喻就是「操做系統可提供給全部進程的存儲空間(虛擬內存空間)正在被某個進程榨乾」,致使的緣由就是程序在運行的時候,會不斷地動態開闢的存儲空間,這些存儲空間在在運行結束以後後並無被及時釋放掉。應用程序在分配了某段內存以後,因爲設計的錯誤,會致使程序失去了對該段內存的控制,形成了內存空間的浪費。golang
若是程序在內存空間內申請了一塊內存,以後程序運行結束以後,沒有把這塊內存空間釋放掉,並且對應的程序又沒有很好的gc機制去對程序申請的空間進行回收,這樣就會致使內存泄露。性能
首先標記root根對象,根對象的子對象也是存活的。優化
根對象包括:全局變量,各個G stack上的變量等。spa
span是內存管理的最小單位,因此猜想gc的粒度也是span。操作系統
如圖所示,經過gcmarkBits位圖標記span的塊是否被引用。對應內存分配中的bitmap區。設計
例如,當前內存中有A~F一共6個對象,根對象a,b自己爲棧上分配的局部變量,根對象a、b分別引用了對象A、B, 而B對象又引用了對象D,則GC開始前各對象的狀態以下圖所示:指針
stop the world是gc的最大性能問題,對於gc而言,須要中止全部的內存變化,即中止全部的goroutine,等待gc結束以後才恢復。orm
GO的GC是並行GC, 也就是GC的大部分處理和普通的go代碼是同時運行的, 這讓GO的GC流程比較複雜.對象
目前整個GC流程會進行兩次STW(Stop The World), 第一次是Stack scan階段, 第二次是Mark Termination階段.blog
從1.8之後的golang將第一步的stop the world 也取消了,這又是一次優化; 1.9開始, 寫屏障的實現使用了Hybrid Write Barrier, 大幅減小了第二次STW的時間.
由於go支持並行GC, GC的掃描和go代碼能夠同時運行, 這樣帶來的問題是GC掃描的過程當中go代碼有可能改變了對象的依賴樹。
例如開始掃描時發現根對象A和B, B擁有C的指針。
爲了不這個問題, go在GC的標記階段會啓用寫屏障(Write Barrier).
啓用了寫屏障(Write Barrier)後,在GC第三輪rescan階段,根據寫屏障標記將C放入灰色,防止C丟失。