go 垃圾回收:三色算法

三色算法

go垃圾回收器的操做都是基於三色算法,這篇文章主要來講明此算法。git

注意:三色算法並非go獨有的,它也會在其它編程語言中使用到

嚴格來講,在Go中這個算法的官方名稱是叫作三色標記清除算法(tricolor mark-and-sweep algorithm)。它能夠和程序一塊兒併發工做而且使用寫屏障(write barrier)。這就意味着,當Go程序員運行起來,go調度器去負責應用程序的調度,而垃圾回收器會像調度器處理常規應用程序同樣,去使用多個goroutines去進行工做。程序員

這個算法背後的核心思想是由Edsger W. Dijkstra,Leslie Lamport,A.J.Martin,C.S.Scholten和E.F.M.Steffens這些大佬提出的。算法首先發表在論文On-the-fly Garbage Collection:An Exercise in Cooperation上面。三色標記清除算法背後的首要原則就是它把堆中的對象根據它們的顏色分到不一樣集合裏面。github

如今讓咱們來談談每種顏色集合表明的含義。黑色集合是爲了確保沒有任何指針指向白色集合。可是白色集合中的對象容許有指針指向黑色集合,由於這不會對垃圾回收器的操做產生影響。灰色集合可能會有指針指向白色集合裏的對象。白色集合中的對象就是垃圾回收的候選對象。golang

注意到沒有任何對象能夠從黑色集合進到白色集合,這容許算法可以去操做而且清除白色集合裏的對象。此外,沒有任何黑色集合裏的指針對象可以直接指向白色集合中的對象。算法

當垃圾回收開始,所有對象標記爲白色,而後垃圾回收器會遍歷全部根對象並把它們標記爲灰色。根對象就是程序能直接訪問到的對象,包括全局變量以及棧裏面的東西。這些對象大多數取決於特定程序的go代碼。在這以後,垃圾回收器選取一個灰色的對象,把它變爲黑色,而後開始尋找去肯定這個對象是否有指針指向白色集合的對象。這意味着當一個灰色對象因爲被其它對象的指針所指而掃描到的時候,這個灰色對象會被標記爲黑色。若是掃描發現這個灰色對象有一個或者更多指針指向白色對象時,會把所指向的白色對象放到灰色集合裏。只要有灰色集合對象存在,這個過程就會一直進行下去。以後,白色集合裏的對象就是沒人訪問的對象,而且它們所佔用的內存能夠被回收重用。所以,在這個點上,咱們說白色集合裏的元素被垃圾回收了。編程

若是垃圾回收過程當中,一個灰色對象在某些狀況變爲不可達狀態,它在那次垃圾回收中就不會被回收了,可是不是說下次也不會回收!

在這個過程當中,運行應用程序被叫作修改器(mutator)。mutator去運行一個小的方法叫作寫屏障(write barrier),每次堆中的指針被修改寫屏障都會去執行。若是堆中對象的指針被修改,就意味着那個對象如今是可觸達的,寫屏障會把它標記爲灰色並把它放到灰色集合中。安全

mutator負責保持黑色集合中沒有任何元素的指針去指向白色集合中的元素。這是在寫屏障方法的幫助下完成的。若是維持這個不變狀態失敗的話,會毀壞垃圾回收過程,而且極可能會以一種醜陋和非預期的方式破壞你的程序。

堆能夠當作許多鏈接對象的圖,以下所示,展現了單獨一個垃圾回收的過程。併發

咱們有三種不一樣顏色:黑色、白色和黑色。當算法開始的時候,全部對象標記爲白色。隨着算法繼續進行,白色對象移到了其它兩種顏色集合的一種裏面。最後留在白色集合裏面的對象會在未來某個時間點被清理掉。編程語言

在前面的圖裏,你能夠看到白色對象E,它是在白色集合裏並且能夠訪問對象F,E不會被任何其它的對象訪問到由於沒有其它指向E的指針,這使得E成爲了垃圾回收的最佳候選人!另外,對象A、B和C是根對象並且老是可達的,所以它們不會被垃圾回收掉。oop

接下來,算法會去處理留下的灰色集合元素,這意味着對象A和F會進入到黑色集合裏。對象A會進入到黑色集合是由於它是一個根元素,而F會進入黑色集合是由於它沒有指向任何其它對象可是是在灰色集合裏。在對象A被垃圾回收以後,對象F會變成不可達狀態而且會在下一次垃圾回收器的處理循環中被回收掉。

Go容許你經過在你的Go代碼裏放一個runtime.GC()的聲明來手動去開啓一次垃圾回收。可是,要記住一點,runtime.GC()會阻塞調用器,而且它可能會阻塞整個程序,尤爲是若是你想運行一個很是繁忙的並且有不少對象的go程序。這種狀況發生,主要是由於你不能在其餘任何事都在頻繁變化的時候去處理垃圾回收,由於這種狀況不會給垃圾回收器機會,去清楚地肯定白色、黑色和灰色集合裏的成員。這種垃圾回收狀態也被稱做是垃圾回收安全點(garbage collection safe-point)

你能夠在https://github.com/golang/go/blob/master/src/runtime/mgc.go裏找到垃圾回收器相關的高級go代碼。你能夠學習這個若是你想了解更多關於垃圾回收操做的東西。

相關文章
相關標籤/搜索