什么是三色標記法
三色標記法是一種用于垃圾回收的算法,被廣泛應用于各類編程語言的垃圾回收器中,包括Go語言。
這種算法將對象劃分成三種顏色:
-
白色:表示對象是垃圾,可以被釋放。也就是說,這是那些從根(root)節(jié)點開始無法觸及的對象。
-
黑色:表示對象是存活的,并且這個對象引用的所有對象也已被訪問和標記。
-
灰色:表示對象是存活的,但是這個對象引用的其他對象還沒有被訪問和標記。
算法開始時,所有對象都標記為白色,然后從根節(jié)點開始遍歷,遍歷到的對象標記為灰色。接著選擇一個灰色對象,把它引用的所有白色對象都標記為灰色,然后把自己標記為黑色。這個過程一直進行,直到?jīng)]有灰色對象。此時,所有存活的對象都被標記為黑色,而所有死亡(不可達或無用)的對象都仍然是白色,GC會回收這些白色對象。
整個過程中的重點在于,如果所有的灰色對象指向的對象都已經(jīng)處理(標記為黑色),則說明所有的可達對象都已訪問(標記為黑色),非黑即白,那么所有的白色對象為不可達對象,可被清理。
Go垃圾回收機制
Go語言的垃圾回收(Garbage Collection,簡稱GC)機制是自動回收系統(tǒng)中不再使用的內(nèi)存的功能。這對于開發(fā)者來說非常方便,因為它省去了手動管理內(nèi)存的需求。
垃圾回收機制在Go語言中的執(zhí)行過程主要由以下幾個步驟組成:
-
標記清除:首先,垃圾回收器會標記出所有生存對象,然后清除所有沒有被標記的對象。
-
并發(fā)標記:在這個階段,垃圾回收器會在用戶goroutine后臺進行,并試圖在標記階段結束之前標記所有的生存對象。
-
標記終止:在這個階段,所有的用戶goroutine都會停止,垃圾回收器會進行最后的檢查并清除所有未標記的對象。
-
掃描:在清除了所有未標記的對象之后,垃圾回收器將進行內(nèi)存清掃,歸還未使用的內(nèi)存給操作系統(tǒng)。
其中,“并發(fā)標記清除”是Go的垃圾回收器的一大特點,它大部分時間與用戶的goroutine并發(fā)執(zhí)行,只有在GC的開始和結束階段才會暫停goroutine。
Go的GC還支持開發(fā)者通過runtime的方法來進行設置和調整,比如設置GC百分比、手動觸發(fā)GC等,以滿足更精細化的內(nèi)存管理需求。
Stop The World
Go語言在執(zhí)行垃圾回收時,會有兩次STW(Stop The World,簡稱停工)事件。
第一次停工事件發(fā)生在垃圾回收的"并發(fā)標記"階段開始之前,這次停工是為了確保所有的goroutine都寫回自己的棧信息,使垃圾回收器能夠正確地找到所有根對象。這次停工的時間通常非常短,因為對棧進行掃描的操作一般很快就能完成。
第二次停工事件發(fā)生在"并發(fā)標記"階段結束后,垃圾回收進入到"標記終止"階段。這次停工主要是為了處理在"并發(fā)標記"階段可能遺漏掉的對象。這個階段包括處理分配在"并發(fā)標記"階段的對象,處理在"并發(fā)標記"階段產(chǎn)生的寫屏障,以及對heap進行最后一次掃描。這次停工的時間與heap的大小、寫屏障的數(shù)量以及"并發(fā)標記"階段分配的對象數(shù)量有關,通常也會盡力控制在可以接受的范圍之內(nèi)。
總的來說,Go語言盡量減少了垃圾回收中的停工時間,同時通過并發(fā)進行垃圾回收,使得Go語言的垃圾回收相較于其他一些語言的垃圾回收,對程序執(zhí)行的影響更小。
以下情況可能會影響Go語言的STW (Stop The World) 的時間:
-
大量的內(nèi)存使用:如果程序使用了大量內(nèi)存,垃圾回收器需要掃描更多的對象,這就可能增加STW的時長。
-
大量的 Goroutine:每個 Goroutine 都會增加STW的時間,因為在兩次STW期間,它們的調度狀態(tài)和棧必須被掃描。
-
寫屏障的開啟狀態(tài):在并發(fā)標記階段,一旦對象被灰度標記,如果應用程序試圖更改該對象,必須先開啟寫屏障來標記任何新分配或者即將被覆蓋的對象。因此,過多的寫操作會增加STW的時間。
-
分配速度:在垃圾回收過程中,如果內(nèi)存分配的速度快于垃圾回收的速度,可能會導致內(nèi)存空間不斷增長,從而延長STW的時間。
這些情形都可能導致STW時間的增加,因此在編寫代碼時,開發(fā)者需要盡量減少內(nèi)存的使用,控制 Goroutine 的數(shù)量,注意內(nèi)存分配的速度等,以更好地管理內(nèi)存并提高程序的性能。