垃圾回收器
垃圾回收是釋放掉那些不再被使用的記憶體空間的程序,
換句話說,垃圾回收器會去檢查哪些物件超出范圍并且不會再被參考到,然后它回去釋放掉那些物件占用的記憶體空間,這個程序實在 go 程式運行中以并發的方式去進行的,不是 go 程式執行之前,也不是 go 程式執行之后,go 垃圾回收器實作的說明檔案給出了如下宣告(runtime 包下的 mgc.go):
The GC runs concurrently with mutator threads, is type accurate (aka
precise), allows multiple GC thread to run in parallel. It is a concurrent
mark and sweep that uses a write barrier. It is non-generational and non
compacting. Allocation is done using size segregated per P allocation
areas to minimize fragmentation while eliminating locks in the common
case.
垃圾回收是和go執行緒同時運行的,它是型別精確的,而且多個垃圾回收線
程可以并行運行,它是一種使用了寫屏障的并發標記清除的垃圾回收方
式,它是非分代和非壓縮的,使用按P分配區域隔離的大小來完成分配,
以最小化碎片,同時消除常見情況下的鎖,
三色演算法
go垃圾回收器的操作都是基于三色演算法,
嚴格來說,在Go中這個演算法的官方名稱是叫做三色標記清除演算法(tricolor mark-and-sweep algorithm),它可以和程式一起并發作業并且使用寫屏障(write barrier),這就意味著,當Go程式員運行起來,go調度器去負責應用程式的調度,而垃圾回收器會像調度器處理常規應用程式一樣,去使用多個goroutines去進行作業,
三色標記清除演算法背后的首要原則就是它把堆中的物件根據它們的顏色分到不同集合里面,顏色是根據演算法進行標記的,
黑色集合是為了確保沒有任何指標指向白色集合,但是白色集合中的物件允許有指標指向黑色集合,因為這不會對垃圾回收器的操作產生影響,灰色集合可能會有指標指向白色集合里的物件,白色集合中的物件就是垃圾回收的候選物件,
注意到沒有任何物件可以從黑色集合進到白色集合,這允許演算法能夠去操作并且清除白色集合里的物件,此外,沒有任何黑色集合里的指標物件能夠直接指向白色集合中的物件,
當垃圾回收開始,全部物件標記為白色,然后垃圾回收器會遍歷所有根物件并把它們標記為灰色,根物件就是程式能直接訪問到的物件,包括全域變數以及堆疊里面的東西,這些物件大多數取決于特定程式的go代碼,在這之后,垃圾回收器選取一個灰色的物件,把它變為黑色,然后開始尋找去確定這個物件是否有指標指向白色集合的物件,這意味著當一個灰色物件由于被其它物件的指標所指而掃描到的時候,這個灰色物件會被標記為黑色,如果掃描發現這個灰色物件有一個或者更多指標指向白色物件時,會把所指向的白色物件放到灰色集合里,只要有灰色集合物件存在,這個程序就會一直進行下去,之后,白色集合里的物件就是沒人訪問的物件,并且它們所占用的記憶體可以被回收重用,因此,在這個點上,我們說白色集合里的元素被垃圾回收了,
在這個程序中,運行應用程式被叫做修改器(mutator),mutator去運行一個小的方法叫做寫屏障**(write barrier)**,每次堆中的指標被修改寫屏障都會去執行,如果堆中物件的指標被修改,就意味著那個物件現在是可觸達的,寫屏障會把它標記為灰色并把它放到灰色集合中,
mutator負責保持黑色集合中沒有任何元素的指標去指向白色集合中的元素,這是在寫屏障方法的幫助下完成的,如果維持這個不變狀態失敗的話,會毀壞垃圾回收程序,并且很可能會以一種丑陋和非預期的方式破壞你的程式,
go垃圾回收也可以應用于其它變數例如channel!當垃圾回收器發現一個channel是不可達的而且channel變數再也不會被訪問到,它就會釋放掉它的資源甚至說channel還沒被關閉!
Go允許你通過在你的Go代碼里放一個 runtime.GC() 的宣告來手動去開啟一次垃圾回收,但是,要記住一點, runtime.GC() 會阻塞呼叫器,并且它可能會阻塞整個程式,尤其是如果你想運行一個非常繁忙的而且有很多物件的go程式,這種情況發生,主要是因為你不能在其他任何事都在頻繁變化的時候去處理垃圾回收,因為這種情況不會給垃圾回收器機會,去清楚地確定白色、黑色和灰色集合里的成員,這種垃圾回收狀態也被稱作是垃圾回收安全點**(garbage collection safe-point)**,
垃圾回收器背后的更多操作
go垃圾回收器的主要關注點是低延遲,也就是說為了進行實時操作它會有短暫的暫停,另一方面,創建新物件然后使用指標操作存活物件是程式始終在做的事情,這個程序可能最侄訓創建出不會再被訪問到的物件,因為沒有指向那些物件的指標,這種物件即為垃圾物件,它們等待被垃圾回收器清理然后釋放它們的空間,之后它們釋放的空間可以再次被使用,
垃圾回收中使用的最簡單的演算法就是經典的標記清除演算法**(mark-and sweep)**:演算法為了遍歷和標記堆中所有可觸達物件,會把程式停下來(stop the world),之后,它會去清掃(sweeps)不可觸達的物件,在演算法的標記(mark)階段,每個物件被標記為白色、灰色或黑色,灰色的子物件標記為灰色,而原始的物件此時會標記為黑色,沒有更多灰色物件去檢查的話就會開始清掃階段,這個技術適用是因為沒有從黑色指向白色的指標,這是演算法的基本不變要素,
盡管標記清除演算法很簡單,但是它會暫停程式的運行,這意味著實際程序中它會增加延遲,go會通過把垃圾回收器作為一個并發的處理程序,同時使用前一節講的三色演算法,來降低這種延遲,但是,在垃圾回收器并發運行時候,其它的程序可能會移動指標或者創建物件,這會讓垃圾回收器處理非常困難,所以,讓三色演算法并發運行的關鍵點就是,維持標記清除演算法的不變要素即沒有黑色的物件能夠指向白色集合物件,
因此,新物件必須進入到灰色集合,因為這種方式下標記清除的不變要素不會被改變,另外,當程式的一個指標移動,要把指標所指的物件標記為灰色,你可以說灰色集合是白色集合和黑色集合中間的“屏障”,最后,每次一個指標移動,會自動執行一些代碼,也就是我們之前提到的寫屏障,它會去進行重新標色,為了能夠并發運行垃圾回收器,寫屏障代碼產生的延遲是必要的代價,
一定要記住,Go垃圾回收器是一個實時的垃圾回收器 ,它是和其他goroutines一起并發運行的
還在找我的道轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/512028.html
標籤:Go
上一篇:java基礎-檔案與IO
