本文主要介紹了垃圾回收的概念,Golang GC的垃圾回收算法和工做原理,看完本文可讓你對Golang垃圾回收機制有個全面的理解。因爲本人不瞭解其餘語言的GC,並未對比其餘語言的垃圾回收算法,須要的能夠自行Google。html
垃圾回收(英語:Garbage Collection,縮寫爲GC),在計算機科學中是一種自動的存儲器管理機制。當一個計算機上的動態存儲器再也不須要時,就應該予以釋放,以讓出存儲器,這種存儲器資源管理,稱爲垃圾回收。垃圾回收器可讓程序員減輕許多負擔,也減小程序員犯錯的機會。來自維基百科git
簡單地說,垃圾回收(GC)是在後臺運行一個守護線程,它的做用是在監控各個對象的狀態,識別而且丟棄再也不使用的對象來釋放和重用資源。程序員
當前Golang使用的垃圾回收機制是三色標記發配合寫屏障和輔助GC,三色標記法是標記-清除法的一種加強版本。github
原始的標記清楚法分爲兩個步驟:算法
這樣作有個很大的問題就是要經過STW保證GC期間標記對象的狀態不能變化,整個程序都要暫停掉,在外部看來程序就會卡頓。markdown
三色標記法是對標記階段的改進,原理以下:併發
那麼什麼是root呢? 看了不少文章都沒解釋這這個概念,在這兒說明下:root區域主要是程序運行到當前時刻的棧和全局數據區域。oop
也能夠參考下面的動圖輔助理解:性能
上面介紹的是GO GC採用的三色標記算法,可是好像並無體現出來怎麼減小STW對程序的影響呢?實際上是由於Golang GC的大部分處理是和用戶代碼並行的。學習
GC期間用戶代碼可能會改變某些對象的狀態,如何實現GC和用戶代碼並行呢?先看下GC工做的完整流程:
寫屏障:該屏障以前的寫操做和以後的寫操做相比,先被系統其它組件感知。 好難懂哦,結合上面GC工做的完整流程就好理解了,就是在每一輪GC開始時會初始化一個叫作「屏障」的東西,而後由它記錄第一次scan時各個對象的狀態,以便和第二次re-scan進行比對,引用狀態變化的對象被標記爲灰色以防止丟失,將屏障先後狀態未變化對象繼續處理。
從上面的GC工做的完整流程能夠看出Golang GC實際上把單次暫停時間分散掉了,原本程序執⾏多是「⽤戶代碼-->⼤段GC-->⽤戶代碼」,那麼分散之後實際上變成了「⽤戶代碼-->⼩段 GC-->⽤戶代碼-->⼩段GC-->⽤戶代碼」這樣。若是GC回收的速度跟不上用戶代碼分配對象的速度呢? Go 語⾔若是發現掃描後回收的速度跟不上分配的速度它依然會把⽤戶邏輯暫停,⽤戶邏輯暫停了之後也就意味着不會有新的對象出現,同時會把⽤戶線程搶過來加⼊到垃圾回收⾥⾯加快垃圾回收的速度。這樣⼀來原來的併發仍是變成了STW,仍是得把⽤戶線程暫停掉,要否則掃描和回收沒完沒了了停不下來,由於新分配對象⽐回收快,因此這種東⻄叫作輔助回收。
衡量GC對程序的影響能夠參考這篇文章,Go 程序的性能調試問題。
減小對象的分配,合理重複利用; 避免string與[]byte轉化;
二者發生轉換的時候,底層數據結結構會進行復制,所以致使 gc 效率會變低。
少許使用+鏈接 string;
Go裏面string是最基礎的類型,是一個只讀類型,針對他的每個操做都會建立一個新的string。 若是是少許小文本拼接,用 「+」 就好;若是是大量小文本拼接,用 strings.Join;若是是大量大文本拼接,用 bytes.Buffer。
自動垃圾回收的觸發條件有兩個:
雖然Golang有自動垃圾回收機制,可是GC不是萬能的,最好仍是養成手動回收內存的習慣:好比手動把再也不使用的內存釋放,把對象置成nil,也能夠考慮在合適的時候調用runtime.GC()觸發GC。
近期在維護的go學習示例代碼,新入坑的朋友們能夠關注下 go-programming。
參考: