天天看點

全局對象_Go垃圾回收之根對象與全局掃描

choose the tool for the problem and do not try to fit the problem for the tool

根對象

在上文中介紹了并行标記的執行模型,後面的幾個小節将具體介紹标記“染色”階段發生的故事。

掃描的第一階段是要掃描根對象。在最開始的标記準備階段,就會統計這次GC一共要掃描多少的對象。每一個具體的序号對應着要掃描的對象和類型。

job := atomic.Xadd(&work.markrootNext, +1) - 1
           

work.markrootNext 會原子的增加,這是因為可能會有多個背景标記協程同時通路該變量。而這也保證了多個背景标記協程 會執行不同的任務。

全局對象_Go垃圾回收之根對象與全局掃描

那麼何為根對象呢?對于三色标記來說,根對象是最基本的對象,從根對象出發,可以找到所有的引用對象即活着的對象。在Go語言中,根對象包括了全局變量(在.bss 和.data段記憶體中)、span中的finalizer的任務數量、以及所有的協程棧。finalizer是Go語言中和某種對象綁定的析構器。當某些對象的記憶體釋放後,需要調用析構器函數,進而完整釋放資源。例如os.File對象使用了析構器函數關閉作業系統檔案描述符,即便使用者忘記了調用close()方法也會釋放作業系統資源。

全局變量掃描

掃描全局變量需要編譯時與運作時的共同努力。在運作時,才能确定全局變量配置設定到了虛拟記憶體哪一個區域,并且如果全局變量有指針的話,在運作時其指針指向的記憶體可能會變化。而在編譯時,可以确定全局變量中哪些位置包含指針,資訊位于位圖ptrmask字段中。ptrmask的每一個bit位都對應了.data段中的一個指針大小(8byte),當bit位為1代表目前位置是一個指針。知道了指針可能的位置,這時,需要 求出 目前的指針在堆區的哪一個對象上,并将目前對象标記為灰色。

全局對象_Go垃圾回收之根對象與全局掃描

有些讀者可能會覺得不可思議,如何能夠通過指針找到指針所在的對象位置呢。這靠的是Go語言記憶體配置設定時,對記憶體的精細化管理。對一個指針,首先找到其在哪一個heapArena當中。heapArena是每一次向作業系統申請配置設定的最小64M大小的區域。

type mheap struct {
	arenas [1 << arenaL1Bits]*[1 << arenaL2Bits]*heapArena
}
           

heapArena結構存儲了許多中繼資料,其中包括了每一個page ID(8 KB) 對應的mspan

spans [pagesPerArena]*mspan
           

是以,可以通過指針的位置找到其對應的mspan,并進而找到其位于mspan中第幾個元素中。當找到此元素确實存在後,會選擇将gcmarkBits對應元素的bit設定為1。表明其已經被标記。同時,将該元素(對象)放入标記隊列中。

全局對象_Go垃圾回收之根對象與全局掃描

在span中,每一個元素在位圖gcmarkBits中都會有标志位表明目前的元素中的對象是否被标記。

全局對象_Go垃圾回收之根對象與全局掃描

finalizer

之前提到finalizer是特殊的對象,其是在對象釋放後會調用的析構器,用于資源釋放。因為析構器不會被棧上或全局變量引用,需要單獨處理。

在标記期間,會周遊mspan中的specials連結清單,掃描finalizer所位于的元素(對象),

for sp := s.specials; sp != nil; sp = sp.next {
			if sp.kind != _KindSpecialFinalizer {
				continue
			}
			...
			scanobject(p, gcw)
			scanblock(uintptr(unsafe.Pointer(&spf.fn)), sys.PtrSize, &oneptrmask[0], gcw, nil)
}
           

并對目前元素(對象)進行掃描,掃描對象的詳細過程将在下一小節介紹。注意在這裡,并不能把finalizer所位于的Span中的對象加入到根對象中,否則我們将失去回收該對象的機會。同時需要掃描析構器結構中的字段fn,因為fn可能指向了堆中的記憶體,并可能會被回收。

推薦閱讀

  • Go垃圾回收之并行标記執行模式

福利 我為大家整理了一份 從入門到進階的Go學習資料禮包 ,包含學習建議:入門看什麼,進階看什麼。 關注公衆号 「polarisxu」,回複  ebook  擷取;還可以回複「進群」,和數萬 Gopher 交流學習。

全局對象_Go垃圾回收之根對象與全局掃描