聽 GPT 講 Go 源代碼 --mgc-go

File: mgc.go

mgc.go 是 Go 語言 runtime 包中的一部分,主要負責 Go 語言的垃圾回收機制 (Garbage Collector) 的實現。

Go 的垃圾回收機制採用了標記 - 清除 (mark and sweep) 算法,其過程主要包括以下幾個步驟:

  1. 標記階段(Marking Phase):從根對象開始,遍歷所有對象標記活動對象,即那些在程序中仍然可達的對象。這個過程使用了三色標記法(Three-color marking algorithm)來提高效率。

  2. 製作工作列表(Making Worklist):將待回收的對象放入工作列表中。這個過程採用了 Write Barrier 策略來避免漏標活動對象,並同時減少在標記階段遍歷整個堆的時間。

  3. 清除階段(Sweeping Phase):釋放那些未被標記的對象的內存空間。此時程序可以重新分配這些內存空間給其他對象。

  4. 內存壓縮(Memory Compaction):對於一些碎片化嚴重的內存區域進行整理,以提高程序的內存使用效率。

mgc.go 文件中記錄了垃圾回收器的狀態,以及負責整個垃圾回收過程中的進程管理,包括在垃圾收集中分配堆內存,清除不再使用的對象等等。它還包含了一些內存管理相關的函數,例如:gc() 函數、bgsweep() 函數等等。這些函數負責執行垃圾回收算法的各個步驟,確保 Go 程序在垃圾回收時的性能和穩定性。


Var:

gcphase

gcphase 是一個表示垃圾回收器所處階段的變量。在 Go 語言的垃圾回收過程中,gcphase 用於判斷垃圾回收器的具體狀態,以確定是否可以執行某些操作或運行特定階段的垃圾回收。

這個變量有以下幾種狀態:

  1. gcNone:沒有進行垃圾回收。

  2. gcMark:進行標記階段。

  3. gcMarkTermination:標記階段結束,準備進入清掃階段。

  4. gcSweep:執行清掃階段。

  5. gcSweepWait:清掃階段結束,等待 goroutine 的結束。

  6. gcFinalize:執行最終清掃和某些其他操作。

gcphase 的作用是用於同步垃圾回收器的不同階段,確保垃圾回收器在不同階段之間的正確轉換。同時,它也可以用於檢查垃圾回收器是否已經完成,以便其他代碼可以安全地使用不再需要清理的內存。

writeBarrier

在 Go 語言中,當進行垃圾回收時,一個重要的操作是標記和清理不再使用的內存。標記操作可以通過遍歷程序中的對象進行標記,而清理操作可以將被標記爲不再使用的對象回收。在進行標記操作時,需要確保對象在被標記後不會再被修改,以避免標記的誤判。

在任何時刻,如果程序中的 Go 程序對指針進行了賦值、傳參、成員訪問或數組訪問操作等,就可能會改變一個對象的地址或者創建新對象,這種情況下就可能出現標記誤判。爲了避免這種誤判,Go 語言引入了 write barrier 機制,也稱爲寫障礙。

write barrier 機制會在程序對指針進行修改時,觸發一個攔截器,在記錄修改前後指針所指向的對象,並標記其爲 “灰色”。

在 Go 語言中,write barrier 實現是在 mgc.go 文件中的 writeBarrier 變量中,這個變量是一個函數類型的值,它會被插入到 Go 語言的運行時系統中的指針賦值和傳遞操作中。每次進行這些操作時,writeBarrier 函數就會被調用,用於實現標記和跟蹤指針操作並記錄它們的變化。

簡而言之,writeBarrier 變量的作用是實現 Go 語言中的寫障礙機制,保證垃圾收集器程序在標記時不會誤判。

gcBlackenEnabled

在 Go 語言中,gcBlackenEnabled 變量是垃圾回收器的一個開關變量,它的值會影響到 GC 的執行行爲。具體來說,當 gcBlackenEnabled 爲 true 時,GC 會默認執行黑色染色算法來標記內存對象的狀態;當 gcBlackenEnabled 爲 false 時,則會禁用黑色染色算法,改用灰色染色算法來標記內存對象狀態。這個算法是用於標記內存對象是否已經被掃描,從而避免對同一內存對象重複掃描的。

gcBlackenEnabled 變量的初始值爲 true,如果用戶程序想要關閉黑色染色算法,可以在程序的運行時環境中通過環境變量 GOGC=off 來禁用。禁用黑色染色算法會帶來一些運行時的開銷,但可以避免由於內存對象的繁多而導致的 GC 暫停過長,從而提高系統的性能。因此,在實際開發中,我們需要根據具體情況,來權衡開啓或者關閉 gcBlackenEnabled 變量。

gcMarkWorkerModeStrings

gcMarkWorkerModeStrings 是用於描述垃圾回收器標記階段的工作模式的變量。垃圾回收器的標記階段是指在程序運行過程中識別出哪些內存塊可以被回收的階段,是垃圾回收器中的重要組成部分。

gcMarkWorkerModeStrings 變量的作用是提供一種可讀性更高的方式來設置和描述垃圾回收器標記階段的工作模式。它允許用戶通過設置不同的字符串來改變垃圾回收器的默認行爲,並以一種更加友好的方式來了解垃圾回收器的工作模式。

具體來說,gcMarkWorkerModeStrings 變量包含了垃圾回收器標記階段的三種不同工作模式,分別是:

  1. "local":表示使用本地緩存來存儲標記的對象,減少線程間同步操作的次數,從而提高標記效率。

  2. "central":表示使用中央緩存來存儲標記的對象,可以加快標記速度,但需要進行更多的線程間同步操作。

  3. "global":表示使用全局緩存來存儲標記的對象,在大型程序中可以更好地利用系統資源,但可能會對程序的運行速度造成一定影響。

通過設置 gcMarkWorkerModeStrings 變量,用戶可以更細緻地控制垃圾回收器標記階段的工作模式,從而優化程序的性能和內存使用。

work

在 Go 語言的 runtime 包中,mgc.go 文件是與垃圾回收(GC)相關的代碼文件之一。其中,work 變量是一個全局變量,主要用於管理和跟蹤 GC 的工作狀態。

work 變量包括了以下字段:

在 Go 語言的垃圾回收算法中,工作緩衝區是用於存儲指向可回收對象的指針的,用於標記這些對象以進行回收。work 變量的作用是確保 GC 的每個階段都處理了所有指向可回收對象的指針,避免出現漏標(對象沒有被標記進行回收)或誤標(無需回收的對象被標記)的情況。

工作緩衝區的大小和分配方式是動態調整的,以充分利用系統資源和避免內存溢出。work 變量的字段 n 和 ptr 是用於管理工作緩衝區大小和分配的指針。同時,備用緩衝區 wbuf1 和 wbuf2 也保證了當 GC 需要在緩衝區溢出時,總能夠快速地進行切換和分配可用的緩衝區。

總之,work 變量是 Go 語言垃圾回收算法中至關重要的一個全局變量,它的作用是管理和跟蹤 GC 的工作狀態,確保 GC 能夠準確地標記和回收內存中的可回收對象,避免內存泄漏和程序崩潰。

gcMarkDoneFlushed

gcMarkDoneFlushed 是在 Go 語言的垃圾回收機制中標記已完成的標誌變量,它主要用於標記已經完成的垃圾回收掃描操作,並告知系統可以繼續執行下一個階段。

具體來說,gcMarkDoneFlushed 變量的作用體現在以下兩個方面:

  1. 標記掃描結束:在 gc 掃描過程中,垃圾回收器需要掃描根據當前 goroutine 的堆棧、靜態變量和全局變量等信息,並跟蹤對象的引用關係來決定哪些對象是存活的,哪些是垃圾對象。當掃描結束時,gcMarkDoneFlushed 變量會被設置爲 true,表示當前階段的掃描已經完成。

  2. 觸發垃圾回收:同時,當已經完成了垃圾回收掃描操作時,系統會檢查 gcMarkDoneFlushed 變量的狀態。如果 gcMarkDoneFlushed 爲 true,說明當前階段的根據引用關係掃描已經完成,垃圾對象已經被標記。這時候垃圾回收機制會啓動垃圾清理過程對標記的垃圾對象進行回收,釋放內存空間。反之,如果 gcMarkDoneFlushed 爲 false,說明垃圾回收掃描操作尚未完成,垃圾回收機制會繼續掃描直到所有對象全部掃描完成。

綜上所述,gcMarkDoneFlushed 變量是垃圾回收機制的一個標記,用於標記垃圾回收掃描階段已完成,並且可以觸發垃圾清理操作,從而實現有效的垃圾回收和內存管理。

poolcleanup

變量名:poolcleanup

作用:這個變量用於指示是否應該在每次垃圾收集後清理池。垃圾收集是指在 Go 程序運行期間由 go runtime 進行的自動內存管理過程。

詳細介紹:

在 Go 中,當我們需要使用大量的臨時對象時,使用池是一種有效的方式來減少內存分配和垃圾回收的開銷。池是帶有同步機制的對象池,它使我們可以重用先前分配的對象以提高性能。

go runtime 中的 poolcleanup 變量控制池的清理時間。如果 poolcleanup 的值爲 true,則在每次垃圾收集後會清理池。這意味着池中的對象會在 gc 期間不會被處理,因此需要在垃圾收集後進行清理以回收資源。

如果 poolcleanup 的值爲 false,則在每次垃圾收集中不會清理池。這可以提高性能,因爲不需要花費額外的時間來清理池,但這也可能會導致池中的對象在過多時間內沒有被回收,從而佔用更多的內存。

在實際編程中,我們可以根據具體的場景來選擇是否需要開啓 poolcleanup。如果池中的對象的生命週期很短,可能沒有必要在每次垃圾收集後清理池。但是,如果池中的對象的生命週期很長,例如在長時間運行的服務器程序中,建議在垃圾收集後清理池,以避免內存泄漏和過多的內存佔用。

boringCaches

變量 boringCaches 是 runtime 中的一個緩存結構。它主要用於加速垃圾回收器中的一部分操作。

在垃圾回收器中,需要頻繁從堆上分配和回收內存。通過 boringCaches,可以實現對部分對象的複用,從而減少分配和回收的次數,提高效率。

boringCaches 的具體實現是一個數組,數組中的每個元素都是一個指向 C 空間的指針。在垃圾回收器的操作中,可以將一些對象存放到 boringCaches 中,然後在需要使用時直接從 boringCaches 中獲取對應的對象,而無需重新分配內存。當對象不再需要時,可以將其放回 boringCaches 中以便複用。

boringCaches 在不同的垃圾回收器中有不同的用途。在 Go 1.5 及之前的版本中,boringCaches 主要用於保存已分配的對象以供下一次使用。而在 Go 1.6 及之後的版本中,boringCaches 也可以用於保存垃圾回收器中的內部數據結構,從而提高運行時的性能。

總之,boringCaches 通過複用一些對象來減少分配和回收的次數,從而提高垃圾回收器的效率。它是垃圾回收器中的一個重要優化措施,也是 runtime 中重要的一個緩存結構。


Structs:

gcMarkWorkerMode

gcMarkWorkerMode 是 Go 語言中垃圾回收器中的一種工作模式,用於在併發標記階段中協調多個標記器的工作。

具體來說,當 Go 語言的垃圾回收器需要回收內存時,它會啓動一個併發的標記階段,即前面提到的階段二。在這個階段中,垃圾回收器會使用多個 goroutine 併發掃描程序中正在使用的堆中的對象,標記活躍對象和垃圾對象。在多核 CPU 上,這個併發掃描的過程更加高效。

而 gcMarkWorkerMode 結構體則是用來控制併發標記過程中的多個標記器的工作,它的主要作用有以下幾個:

  1. 維護標記隊列。在併發標記過程中,標記器會使用 work.markfor 掃描堆中的對象,標記活躍的對象並放入標記隊列中。gcMarkWorkerMode 結構體中的 markfor 屬性會存儲這個標記隊列的指針,用來協調多個標記器之間的工作,避免衝突和重複工作。

  2. 控制標記器的運行狀態。gcMarkWorkerMode 結構體中的 stop 和 shutdown 等屬性可以控制標記器的運行狀態,根據需要中途停止標記器的掃描工作。

  3. 提供線程安全的接口。gcMarkWorkerMode 結構體中的 pushgrey 和 commitgrey 等方法可以提供多個標記器之間的線程安全的接口,避免衝突和數據競爭。

總之,gcMarkWorkerMode 結構體是 Go 語言中垃圾回收器中實現併發標記的重要組成部分,它能夠協調多個標記器之間的工作,提高垃圾回收的效率。

workType

workType 結構體是垃圾收集器的核心數據結構之一,主要用於保存和管理工作線程(G),用於協調和執行垃圾收集的任務。該結構體定義如下:

type workType struct {
    victim      uintptr           // 下一個被掃描對象的地址
    nobj        uintptr           // 當前掃描對象的數量
    obj         uintptr           // 當前正在掃描的對象地址
    bytesMarked uint64            // 當前線程剛完成標記的 bytes 數量
    scanp       uintptr           // 當前指向的對象或者下一個對象的地址
    gcw         *gcWork           // 當前工作線程的 gcWork 結構指針
    scanner     *scanState        // 掃描過程中的狀態信息
    nest        int32             // 嵌套的 for 循環層數(用於調試)
    // ...(其他字段省略)
}

其中,主要有以下幾個字段:

總的來說,workType 結構體在垃圾收集器中發揮着至關重要的作用,它是維持工作線程和垃圾收集器協同工作的關鍵所在。通過該結構體,垃圾收集器可以跟蹤工作線程的掃描進度、協調各工作線程的掃描工作、發現全局存活對象等,從而實現對整個堆中存活對象的準確標記和回收。

gcMode

gcMode 結構體定義了運行時的垃圾回收模式以及一些相關參數,用於控制垃圾回收的行爲。具體來說,gcMode 結構體包含了以下字段:

通過調整 gcMode 結構體的字段值,可以靈活地控制垃圾回收的觸發和行爲,進而影響程序的性能和穩定性。例如,可以通過修改 triggerRatio 和 heapMaximum 來調整垃圾回收的頻率和堆大小,從而優化程序的內存使用和垃圾回收的效率。

gcTrigger

在 Go 語言中,gcTrigger 結構體用於控制 GC 觸發的條件。在 Go 運行時,GC 需要在某些情況下觸發,以回收不再使用的內存。gcTrigger 結構體中定義了一些用於控制 GC 觸發條件的屬性和方法。

gcTrigger 結構體包含以下屬性:

  1. memstats:用於存儲內存統計信息的結構體。

  2. gcSystemStartTime:系統啓動時間。

  3. lastGCPauseEndTime:上一次 GC 暫停結束時間。

  4. triggerRatio:可被 GC 回收的堆內存佔總內存的比例閾值。

  5. triggerBytes:可被 GC 回收的堆內存大小的閾值。

  6. lastTriggerRatio:上一次垃圾回收時可被回收的堆內存佔總內存的比例。

  7. lastTriggerBytes:上一次垃圾回收時可被 GC 回收的堆內存大小。

gcTrigger 結構體包含以下方法:

  1. setTriggerRatio(ratio float64):設置 gcTrigger 的 triggerRatio 屬性。

  2. setTriggerBytes(bytes uint64):設置 gcTrigger 的 triggerBytes 屬性。

  3. trigger():判斷是否需要觸發 GC。當可被 GC 回收的堆內存大小超過 triggerBytes 或可被回收的堆內存佔總內存的比例超過 triggerRatio 時,觸發 GC。

總之,gcTrigger 結構體中的這些屬性和方法用於控制 GC 的觸發條件,以確保 GC 能夠在適當的時間回收內存,提高 Go 程序的性能和穩定性。

gcTriggerKind

在 Go 語言中,GC(垃圾回收)被用來自動管理內存。有時,垃圾回收程序會在應用程序正在運行時突然觸發,這可能會導致不必要的性能開銷。

爲了避免這種情況,Go 語言在 runtime/mgc.go 中定義了一個名爲 gcTriggerKind 的結構體,用於描述垃圾回收觸發的類型。

gcTriggerKind 結構體的作用是描述垃圾回收的類型,包括它是由內存分配還是使用量觸發的、它是否由手動觸發、以及它的嚴格程度等等。

具體來說,gcTriggerKind 結構體包含以下屬性:

通過 gcTriggerKind 結構體,我們可以靈活地控制垃圾回收的觸發類型和頻率,從而平衡應用程序的性能和內存使用。

gcBgMarkWorkerNode

在 go/src/runtime/mgc.go 文件中,gcBgMarkWorkerNode 結構體是用於表示與 BGMarkWorker 相關的狀態的一種類型。它的定義如下:

// A gcBgMarkWorkerNode is a node in the concurrent work queue of
// the background mark worker. Thus it is an element of the doubly-
// linked list defined by the gcBgMarkWorkerState.
//
// One gcBgMarkWorkerNode is used to represent both the state of being
// enqueued for work and the state of being processed but not yet
// enqueued for the next phase of the mark worker.
//
// Depending on the state of the gcBgMarkWorkerState, it is mutable
// from one of potentially many concurrent GC workers or the mark worker
// itself; however, each transition MUST be made under the appropriate
// lock.
//
// Rather than label each and every field below as mutable or not,
// it is crucial to keep in mind the following invariant:
//
// The fields are only modified when the state is actively enqueued 
// or being dequeued. This doesn't overlap with the currently active 
// gcBgMarkWorkerState because each phase of the mark worker has a 
// private immutable snapshot of the work queue that is shuffled 
// independently of any other phase. If two phases are executing 
// concurrently (which would happen during "on-the-fly" single-P 
// marking or D phase)then they split the work hand over fist 
// rather than interleaving.
type gcBgMarkWorkerNode struct {
    // A node struct must start with a gcWork.
    work gcWork

    // Popped off the current mark queue.
    next *gcBgMarkWorkerNode
    prev *gcBgMarkWorkerNode

    // live == live objects; dead == garbage.
    leaf bool
    live uintptr
    dead uintptr
    target  *gcBgMarkWorkerState
}

在併發垃圾回收器中,每個後臺標記 worker 都維護着一個併發工作隊列(concurrent work queue)。gcBgMarkWorkerNode 結構體就是這個隊列中的元素。它有以下幾個成員:

gcBgMarkWorkerNode 的主要作用是:

Functions:

gcinit

gcinit 函數是 Go 語言垃圾回收機制的初始化函數,它會在程序啓動時被調用。gcinit 會負責以下幾個任務:

  1. 設置全局變量 gcphase 的初始值爲_gcoff。gcphase 用來記錄當前垃圾回收的階段,具體取值可以是_gcoff、_gcmark、_gcmarktermination、_gcSweep、_gcSweepDone 等,不同階段對應不同的垃圾回收操作。

  2. 初始化工作線程。在 Go 語言的垃圾回收過程中,需要使用多個工作線程來並行標記和清理內存。gcinit 會創建一組工作線程,並將它們初始化,準備好執行垃圾回收任務。

  3. 設置全局變量 gcController。gcController 用來控制垃圾回收的流程,包括階段轉換和線程調度等,gcinit 會初始化 gcController 並將其設置爲正在進行的垃圾回收的控制器。

  4. 初始化 P 的本地緩存。在 Go 語言的垃圾回收過程中,每個工作線程都會維護一個本地緩存(Local Cache),用來保存一些臨時變量和對象。gcinit 會將所有工作線程的本地緩存初始化,並將它們和全局變量 gcController 進行關聯。這樣,每個工作線程都可以將本地緩存中的內容同步到全局緩存中,保證垃圾回收的正確執行。

總的來說,gcinit 函數的作用是初始化垃圾回收機制的各個組件,爲垃圾回收做好準備工作,保證其正確、高效地執行。

gcenable

在 Go 語言中,垃圾回收是由運行時系統負責的。gcenable 是運行時系統中的一個函數,其作用是啓用垃圾回收。

具體來說,gcenable 函數會將標記位從 _GCoff 修改爲 _GCmark,並觸發一次強制執行的垃圾回收操作。此外,gcenable 函數還會檢查其他相關參數,如 gcpercent(觸發垃圾回收的最低堆使用量)和 maxprocs(最大併發執行的進程數),以確保垃圾回收系統正常運行。

在啓用垃圾回收之前,應用程序可能需要完成一些初始化工作。例如,創建一些 goroutine、分配內存等等。一旦這些初始化完成,應用程序可以調用 gcenable 函數,以啓用垃圾回收系統。

總之,gcenable 函數是 Go 運行時系統中的一個關鍵功能,它使得垃圾回收可以正常工作,確保了 Go 代碼的穩定性和可靠性。

setGCPhase

setGCPhase 函數是用於設置當前的垃圾回收階段的函數。垃圾回收階段包括 STW (Stop-The-World)、Mark、MarkTermination、Sweep、SweepTermination 等。該函數如果被調用時未處於 STW 階段,會拋出錯誤。

具體來說,當程序需要進行垃圾回收時,Go runtime 會按照垃圾回收階段的順序進行不同的操作。setGCPhase 函數就是用來在不同階段中切換的函數,例如在 Mark 階段時調用 setGCPhase 函數來切換到 MarkTermination 階段。另外,在切換不同階段時需要進行一些涉及到全局狀態的操作,例如更新 P 的狀態、清空緩存等,經常會調用一些相關的函數,以便在不同階段中進行必要的全局操作。

總之,setGCPhase 函數主要作用是在垃圾回收過程中切換不同的階段,並進行一些涉及到全局狀態的操作。它是 Go runtime 中垃圾回收部分的關鍵函數之一。

pollFractionalWorkerExit

pollFractionalWorkerExit 函數是用於檢查並退出 Goroutine 的函數。在併發垃圾回收(Concurrent Garbage Collection,簡稱 CGC)中,有專門的 Goroutine 用於協助 GC 完成其中的一些任務,這些 Goroutine 稱爲 helper goroutine,它們是在應用程序正常執行的情況下運行的。但是,由於這些 helper goroutine 不會自行退出,它們可能會佔用應用程序中的一些資源並降低性能。pollFractionalWorkerExit 函數的作用就是用於檢查這些 helper goroutine 是否有退出的機會,如果可以退出,就會強制讓它們退出。

在函數實現中,pollFractionalWorkerExit 會獲取 helper goroutine 的一份副本,通過檢查副本的狀態來判斷是否有退出的機會。如果 helper goroutine 的副本狀態處於 waitexit 狀態(這意味着 helper goroutine 已經準備好退出了),則將其從 goroutine 隊列中移除,並設置 helper goroutine 的狀態爲 exited。如果 helper goroutine 的狀態不是 waitexit,則僅僅是將其副本狀態設置爲 pollidle 狀態,以便後續輪詢。

pollFractionalWorkerExit 函數一般是由 pollFractionalWorker 函數調用的,用於輪詢並退出 helper goroutine。通過這種方式,可以保證 helper goroutine 不會無限制地佔用資源,從而保持應用程序的性能穩定。

GC

GC 是 Golang 的垃圾回收機制,它的作用是在程序運行的過程中對內存進行自動化管理,保證程序能夠自動回收不再使用的內存,防止內存泄露和程序崩潰。

在 Go 語言的 GC 實現中,mgc.go 文件中的 GC 函數是其中最爲核心的部分,它負責對程序的內存進行回收。GC 函數會使用可達性分析算法來檢查哪些內存是可達的,哪些是不可達的,對於不可達的內存會自動回收。

GC 函數的流程大致如下:

  1. 通過遍歷 G、P、M 等數據結構獲取所有的根對象,根對象是程序中所有被引用的對象的入口點。

  2. 對所有根對象進行遍歷,標記所有可達的對象爲活動對象,不可達的對象則是垃圾對象。

  3. 對於所有不可達的對象,調用對象的 finalizer,讓其執行垃圾回收前的清理工作。

  4. 對於所有不可達且沒有 finalizer 的對象,直接將其回收。

  5. 經過垃圾回收後,將回收的內存重新分配給空閒列表,以便下一次的內存分配使用。

需要注意的是,在執行 GC 函數時,程序需要停止所有的 goroutine 並暫停程序的正常運行,等待 GC 完成後再恢復程序的執行,這個過程稱爲 “Stop The World”(暫停世界)。

GC 函數會在程序的一些關鍵點自動觸發,例如當堆大小達到一定閾值、或當程序調用了 runtime.GC() 函數時,GC 函數會對內存進行自動回收。

gcWaitOnMark

gcWaitOnMark 是 runtime 中的一個函數,主要目的是等待標記階段的完成。

在 Go 語言的垃圾回收中,標記階段是 GC 的一部分。在這個階段中,GC 會標記所有已分配對象中仍然在使用的對象。標記完畢後,GC 就會知道哪些對象可以被回收,哪些對象仍然在使用中。但是,等待標記階段的完成可能會降低應用程序的性能,因此,gcWaitOnMark 函數的作用就是提高並行性,加快標記階段的完成。

具體來講,gcWaitOnMark 函數的工作是阻塞當前 goroutine,等待標記階段完成。如果標記階段已經完成,那麼函數立即返回。否則,函數會調用 gcController、gcBgMarkWorker 和 gcMarkDone 等函數來進行協調和等待。當標記階段完成後,函數會返回並繼續執行後續操作。

總之,gcWaitOnMark 函數的作用就是等待 GC 標記階段的完成,並最大限度地提高並行性,加快標記階段的完成。

test

在 go/src/runtime/mgc.go 文件中,test func 主要是用於:

  1. 驗證小對象內存分配是否正常

  2. 確保可達性分析過程不會出現死循環,保證垃圾回收不會影響應用程序的正常運行

具體來說,test func 會創建一些小對象(allocs)並且在子協程裏分配和釋放它們,測試系統是否可以正常擴展堆空間。如果分配和釋放正常完成,則說明內存分配系統正常工作。在分配和釋放這些對象時,堆大小也會動態調整以適應需要。

測試還會模擬垃圾回收過程,即執行強制垃圾回收,然後檢查回收後的堆大小是否正確。如果大小正確,則說明垃圾回收器正常工作,並且不會對應用程序的正常運行產生影響。

測試還會驗證標記過程是否正常完成,即在分配和釋放這些小對象後,會標記所有可達對象,以確保可達性分析過程不會進入死循環狀態。

總之,test func 是用於驗證垃圾回收器正常工作,並確保不會對應用程序的正常運行產生影響的重要函數。

gcStart

gcStart 是 Go 語言運行時底層的垃圾回收器(GC)開始執行的函數。它主要有以下幾個作用:

  1. 初始化 GC 相關數據結構:gcStart 會初始化標記位圖、堆棧緩存、roots 集合等數據結構。這些數據結構是 GC 執行過程中必要的。

  2. 標記根對象:GC 開始前需要明確哪些對象是可達的根對象,即哪些對象是從外部引用的或者是全局變量。gcStart 會標記這些根對象以確保它們不會被回收。

  3. 調用標記階段的回調函數:GC 執行過程中有一些回調函數會被調用,比如記錄對象信息的回調、處理 finalizer 的回調等。gcStart 會調用標記階段的回調函數。

  4. 標記完整個堆:經過前面的準備工作後,gcStart 會開始執行標記階段,遍歷整個堆,將可達對象標記爲活動對象,未被標記的對象爲垃圾對象。

  5. 執行清理階段:當標記階段結束後,gcStart 會執行清理階段,將所有未被標記的對象(即垃圾對象)回收。清理過程包括與其它 goroutine 協作完成的事宜,例如中斷時間的清理,將被釋放的內存歸還給操作系統等。

總體來說,gcStart 是 Go 語言運行時 GC 的引擎,它通過在標記階段標記活動對象,清理階段回收垃圾對象,並在整個垃圾回收過程中調用相關回調函數,保證了 Go 語言程序的內存安全和高效使用。

gcMarkDone

在 Go 語言中,gcMarkDone 函數是用於標記已完成的標記階段的。在垃圾回收過程中,標記階段的任務是從根對象出發,標記所有可達的對象。標記完成後,就可以進行垃圾回收。gcMarkDone 函數的作用是將已完成的標記階段狀態設置爲 done,以便進行下一階段的垃圾回收。在 gcMarkDone 函數中,通過將相關的標記位設置爲已完成來標記標記階段已完成。在標記階段完成後,我們可以安全地清理任何未被使用的內存。同時,gcMarkDone 函數還會調用 gcSweep 函數來執行掃描操作,並將未被使用的內存釋放回系統。

總之,gcMarkDone 函數是用於標記完成垃圾回收中的標記階段並清理未使用的內存。它是 Go 語言垃圾回收流程中非常重要的一個環節。

gcMarkTermination

gcMarkTermination 函數是垃圾回收器在併發標記階段結束時調用的函數之一,它的作用是將一些未被掃描的對象標記爲黑色,並把它們添加到黑色對象列表中。具體來說,gcMarkTermination 會做以下三件事情:

  1. 掃描 grayobject 列表,將其中仍未被掃描的對象標記爲黑色。

  2. 掃描 graySpecial 列表,將其中的特殊對象(如 g 或 m)標記爲黑色。

  3. 將一些未被掃描的堆對象(如跨度對象或大對象)標記爲黑色,這些對象在掃描階段可能被遺漏。

通過以上三個步驟,gcMarkTermination 函數可以確保所有的可達對象都被正確標記爲黑色,以使垃圾回收器能夠正確識別哪些對象應該被保留,哪些對象應該被釋放。

總之,gcMarkTermination 函數是垃圾回收器併發標記階段的一個重要組成部分,它通過掃描未被正確標記的對象,最大程度地減少垃圾回收的誤判和漏判,從而更加高效地回收內存。

gcBgMarkStartWorkers

gcBgMarkStartWorkers 函數是 Go 語言標準庫中 runtime 包中 mgc.go 文件中的一個函數,這個函數的主要作用是啓動後臺標記的工作。在 go 程序中,當堆中對象數量達到一定閾值時,需要進行垃圾回收,這個閾值就是 GC 觸發器的閾值。在垃圾回收過程中,需要標記和回收不再使用的對象,這個過程需要佔用 CPU 和內存資源,會影響應用程序的性能。

gcBgMarkStartWorkers 函數的作用就是通過啓動後臺標記工人來降低 GC 對應用程序的影響。在這個函數內部,會檢查當前是否有後臺標記工人在運行,如果沒有,則根據當前 CPU 數量創建 n 個後臺標記工人,並啓動它們,這樣可以併發的運行標記過程,從而減少 GC 對應用程序造成的瓶頸。這些後臺標記工人會在標記過程中協調採樣器和全屏掃描工作,以及在標記完成後執行清洗、壓縮和其他後處理工作,最終完成垃圾回收的過程。

(gcBg)MarkStartWorkers 函數是 gcBackgroundMarkRunLoop 函數調用的子函數,而 (gcBg)MarkStartWorkers 函數起到類似創建並啓動 goroutine 的作用,即爲 Mark State 申請和釋放 P 以及創建和運行 G 的工作。在輸入參數的情況下,返回一組操作 future(並且保證他們都進行,以及回到調用者)。對於未處理可能的錯誤,(gcBg)MarkStartWorkers 處理了它們並且不會退出。從某種意義上說,這種方法實施了類似於實現操作系統中涉及異常和保護策略的方式。

gcBgMarkPrepare

gcBgMarkPrepare 是 Go 語言運行時中 mgc.go 文件中的一個函數,其作用爲在後臺標記階段開始前準備標記。下面是該函數的詳細解釋:

  1. 首先,該函數會獲取 gcController 狀態(gc 背景標記控制器)並檢查標記過程是否被取消(stopped)。

  2. 接着,它會檢查待處理的 goroutine 數量,如果沒有,則更新 gcMarkWorkerMode 的狀態爲 markDone 並返回。

  3. 如果仍有待處理的 goroutine,它會首先檢查當前 P(處理器)是否已準備好使用,並且當前的 gcMarkWorkerMode 狀態是否爲 “推送”(pullWait)。

  4. 如果是,則將 gcMarkWorkerMode 更新爲 “推送”(pulling),並返回將該 P 置於推卡片隊列中的信號。這意味着其它 goroutine 將在 P 準備好時推送任務。

  5. 如果當前 P 沒有準備好,則將 gcMarkWorkerMode 更新爲 “阻斷”(blocking),並在進入阻塞之前重新檢查是否進入狀態 stopped。如果狀態未更改,則當前 G(goroutine)將會進入休眠狀態,直到某個 P 可用。

  6. 如果當前 gcMarkWorkerMode 狀態爲 “推送”,則檢查是否有等待推卡片的 goroutine。如果沒有,則更新 gcMarkWorkerMode 爲 “推送完成”(markWait),返回並繼續進行標記。

  7. 如果有等待推卡片的 goroutine,則將它們放置在卡片推送隊列的末尾,並將 gcMarkWorkerMode 更新爲 “推送完成”(markWait),返回並繼續進行標記。

總之,gcBgMarkPrepare 函數用於在標記階段啓動前準備標記,根據當前狀態(例如,準備好的處理器數量和待處理的 goroutine 數量)推送或阻塞 goroutine 以優化標記過程。

gcBgMarkWorker

gcBgMarkWorker 函數是 Go 語言的垃圾回收器背景標記階段的工作者函數,它的作用是協調和執行背景標記階段的任務。

在 Go 語言中,垃圾回收分爲兩個階段:標記階段和清理階段。在標記階段中,GC 會標記哪些對象是可達的,而背景標記則是在程序繼續執行的同時進行的。gcBgMarkWorker 函數就是在背景標記階段中發揮作用的。

gcBgMarkWorker 函數的具體工作流程如下:

  1. 獲取 P(processor):gcBgMarkWorker 函數會獲取一個 P(processor),該 P 將用於執行 G(goroutine)中的任務。

  2. 獲取任務:gcBgMarkWorker 函數會獲取一個任務,該任務是從全局隊列中獲取的,用於標記已分配的對象。

  3. 執行任務:gcBgMarkWorker 函數會將獲取到的任務分配給 P 執行。

  4. 解鎖:執行完任務後,gcBgMarkWorker 函數會解鎖其他任務,然後再次獲取 P 和任務執行。

  5. 循環執行:gcBgMarkWorker 函數會一直循環執行 2-4 步,直到全局隊列中沒有待處理任務爲止。

通過這些步驟,gcBgMarkWorker 函數可以協調和執行背景標記階段的任務,並進行高效的垃圾回收。

gcMarkWorkAvailable

gcMarkWorkAvailable 函數是 Go 語言中的垃圾回收機制(GC)的核心函數,在 gcMarkWorkAvailable 函數中,會檢查是否有更多的垃圾標記工作需要執行。如果需要執行更多的垃圾標記工作,則它會將 gcMarkWork.wakeup 中的 goroutine 喚醒。

這個函數的主要作用是確保標記階段中的所有垃圾標記工作都能夠得到充分的處理,從而最大程度地減少垃圾回收的時間和頻率。它在標記階段中被多次調用,以確保所有的垃圾標記工作都能得到處理。

在 Go 語言中,GC 的性能是非常重要的,因爲它直接影響了代碼的執行速度和響應時間。gcMarkWorkAvailable 函數通過檢查是否有更多的垃圾標記工作需要執行,讓 Go 語言的垃圾回收機制更加健壯和高效。

gcMark

gcMark 函數是 Go 語言中 Garbage Collector 的其中一個核心函數,其主要作用是標記所有的存活對象。

在 Garbage Collection 算法中,標記階段是非常重要的一環。簡單來說,gcMark 函數的作用就是通過遍歷對象圖,來標識哪些對象是被程序引用的,還需要被保留下來,而哪些是垃圾,需要被回收。

gcMark 函數的執行流程如下:

  1. 初始化根對象集合

該函數會在程序的全局變量、虛擬機棧、寄存器等計算機內存區域中找出所有的指針對象,並將其加入到根對象集合中。

  1. 遍歷對象圖

接下來,該函數會從根對象集合中取出一個對象,進而遍歷相關的所有對象,標記它們爲活動對象,即便標記它們的顏色爲灰色。

  1. 標記灰色對象的相關對象

在上一步中,所有被標記爲灰色的對象都是需要被細節掃描的。在這一步中,gcMark 函數會遍歷這些灰色對象引用的所有對象,並標記它們爲活動對象。

  1. 標記結束

gcMark 函數將結束標記過程,並將被標記爲活動對象的對象從灰色變爲黑色,此時標記階段結束。

總之,gcMark 函數的作用是負責標記存活對象,使得垃圾回收器能夠在後續的階段中準確地回收無用對象,從而保證程序的內存安全和穩定性。

gcSweep

gcSweep 這個函數的作用是清除不再使用的對象,並將其返回給還未使用的空間池。gcSweep 函數實現了垃圾回收中的標記 - 清除階段,在清除過程中,它掃描程序中的所有對象,並標記那些還在使用的對象,將不再使用的對象清除。

在清除階段,gcSweep 函數會遍歷所有的堆區,找到已經死亡的對象,然後將它們的空間返回給空閒內存池,以便能夠爲後續的對象分配更多的內存。gcSweep 函數會使用一個指針列表,該列表存儲所有被分配的對象的指針,以便在清除時進行遍歷。

在清除階段的最後,gcSweep 函數會更新垃圾回收器的狀態,並準備進入下一個階段。該函數還會更新堆的統計信息,在垃圾回收的過程中記錄已處理的對象數量,並更新堆的大小等信息,以便在下一次垃圾回收時使用。

總之,gcSweep 函數是垃圾回收的關鍵之一,可以通過清除不再使用的對象,釋放內存並提高程序的性能。

gcResetMarkState

gcResetMarkState 是在 Go 語言中垃圾回收器 (gc) 的運行過程中調用的一個函數,它的作用是重置垃圾回收器中與標記相關的狀態,以便下一輪垃圾回收能夠正確地進行。

在 Go 語言中的垃圾回收器執行過程中,需要分爲兩個階段: 標記階段和清掃階段。在標記階段中,會從根對象出發,遍歷所有能夠到達的對象,並將這些對象標記爲活動對象。在這個過程中,爲了防止對象被多次標記或者不被標記的情況出現,需要記錄一些狀態,並在完成標記後進行清理。

gcResetMarkState 函數就是負責重置這些狀態的函數。具體來說,它會清理各種指針標記位,還會重置某些內存區域的狀態,以防止垃圾回收器在下一輪迴收時受到干擾。

總之,gcResetMarkState 函數是垃圾回收器中關鍵的重置函數之一,它確保垃圾回收器在下一輪運行前的狀態是正確的,這樣才能準確地找到所有的垃圾對象進行回收。

sync_runtime_registerPoolCleanup

sync_runtime_registerPoolCleanup 是在 Go 語言中用於垃圾回收的一個函數,定義於 runtime/mgc.go 文件中。它的作用是向全局池(global pool)中註冊一個清理函數(cleanup function),以便在每個垃圾回收週期結束後自動執行。

具體來說,垃圾回收器在回收過程中會創建一些臨時對象,例如內存塊和臨時指針等。這些對象會存在於全局池中,等待下一輪垃圾回收週期結束後清理。如果不及時清理這些對象,將會導致內存泄漏和系統性能下降。

爲了解決這個問題,Go 語言提供了一個在垃圾回收週期結束後自動執行的全局清理函數機制。這個函數由 sync_runtime_registerPoolCleanup 註冊,並在垃圾回收器的全局清理函數調度器中執行。它的作用是清理全局池中的臨時對象,以便下一輪垃圾回收器能夠重新使用它們。

總之,sync_runtime_registerPoolCleanup 函數的作用是向全局池中註冊一個清理函數,用於自動清理垃圾回收中產生的臨時對象,以提高系統的性能和穩定性。

boring_registerCache

boring_registerCache 是 Go 語言的垃圾回收器(GC)中的一個函數,它的作用是註冊一塊新的緩存區域,以供垃圾回收器使用。

在 Go 語言中,當程序中的某個內存塊不再被使用時,垃圾回收器會將這個內存塊標記爲垃圾,並將其回收。GC 會掃描程序的內存空間,識別出那些已經不再使用的內存塊,然後將它們釋放回操作系統。爲了進行這個操作,GC 需要維護一些緩存區域,以記錄哪些內存塊可以被回收。

boring_registerCache 就是用來註冊這些緩存區域的函數。當程序創建一個新的對象時,GC 會調用這個函數來爲該對象分配一個緩存區域。當這個對象不再使用時,GC 會將它從緩存區域中刪除,並將它標記爲垃圾。

這個函數的名字中包含了 “boring” 一詞,意思是它是垃圾回收器中的一個平凡的函數。因爲大多數情況下,程序員很少需要直接調用這個函數,因爲 Go 語言的 GC 會自動進行垃圾回收,而無需程序員手動干預。

clearpools

clearpools 函數定義在 mgc.go 文件中,它的原型如下所示:

// clearpools flushes all cached memory in the runtime.
// This includes mcache and deferred mspan frees.
// It must be called without any other locks held.
// Otherwise it is free to block or allocate memory itself.
// This function is not safe for concurrent invocation.
func clearpools() {
    // ...
}

該函數的作用是清空所有的內存池(memory pool),包括 mcache 和 deferred mspan 釋放。內存池是在運行時(runtime)中由內存管理器(memory manager)分配和管理的一組預定義大小的內存塊。這些內存塊用於跟蹤和分配堆對象和棧幀等運行時數據結構。內存池減少了在分配內存時的系統調用次數,從而提高了運行時的性能。

clearpools 函數必須在沒有其他鎖被持有的情況下調用,否則它可能阻塞或分配內存。此外,該函數不適用於併發調用。因此,它通常在垃圾回收期間被調用,以確保垃圾回收器能夠正確訪問和管理所有內存池。它還可以在程序退出時調用,以釋放所有未釋放的內存池並確保程序退出時沒有內存泄漏。

itoaDiv

itoaDiv 是一個用於將一個無符號整數轉化成字符串的函數,它被用於掃描堆中對象,給對象分配編號,並將這些編號序列化成字符串。

itoaDiv 函數的作用如下:

  1. 將一個無符號整數 num 轉換爲字符串,使用的是基於 10 進制的轉換方式。

  2. 通過除法、取模來實現轉換,divVal 和 divMod 分別用來表示除數和模數。

  3. 從低位到高位依次填充字符串,num 被 divVal 整除的結果不斷被填充到字符串的末尾,直至 num 被 divVal 整除的結果爲 0。

  4. 序列化過程中默認使用的字符集是 ASCII 表中的數字字符。

這個函數主要用於在進行垃圾回收時,將對象的編號序列化成字符串,以便於對這些對象進行跟蹤和調試,並在一定程度上提高了垃圾回收的效率。

fmtNSAsMS

在 go/src/runtime 中,mgc.go 文件中的 fmtNSAsMS 函數的作用是將納秒時間格式的數字轉換爲人類可讀的毫秒時間格式的字符串,例如將 1000000 轉換爲 "1ms"。

該函數接收一個表示納秒時間的 int64 類型參數,首先會根據這個數值來確定要轉換成多少毫秒,然後再根據毫秒數的大小來選擇不同的單位(ms, us, ns)。最後,將轉換成的值和單位拼接起來並返回一個字符串。函數的實現過程中還包括了數值的四捨五入處理,以便得到更精確的結果。

這個函數通常用於在 GC 過程中輸出日誌和統計信息,幫助開發人員瞭解 GC 的執行情況和性能表現。

gcTestMoveStackOnNextCall

gcTestMoveStackOnNextCall 函數是一個用於測試的輔助函數,主要用於模擬在垃圾回收過程中,在函數調用時需要將當前堆棧移動到新的堆棧上的情況。

具體來說,當垃圾回收器對堆進行垃圾回收時,會掃描堆棧中的指針以確定哪些對象在使用中,哪些對象可以被釋放。但是,在進行垃圾回收的時候,會出現堆棧需要移動的情況。因爲垃圾回收的過程中,會存在壓縮堆或者調整堆的情況,如果此時繼續向堆棧上分配內存,會影響以後的垃圾回收,所以需要將已經分配的堆棧移動到新的地方。

gcTestMoveStackOnNextCall 函數就是用於模擬這種場景的測試函數,當該函數調用時,會返回一個新的棧地址,然後將當前堆棧移動到這個新的地址上,從而模擬在垃圾回收過程中堆棧需要移動的情況。

可以看出,gcTestMoveStackOnNextCall 函數在運行時垃圾回收的時候起到了非常重要的作用,它可以幫助開發人員測試代碼在垃圾回收過程中的正確性,而不需要真的進行堆棧移動操作,從而提高了開發效率和代碼質量。

gcTestIsReachable

gcTestIsReachable 是用來測試一個對象是否可以被標記爲可達狀態的函數。

在垃圾回收器中,需要掃描整個堆來標記所有可達的對象。對於每個需要掃描的對象,gcTestIsReachable 函數會被調用來確定該對象是否是可達的。如果對象可達,它將保留在堆中,並繼續被使用。否則,它將被垃圾回收器標記爲不可達,並在下一次垃圾回收時被清除。

gcTestIsReachable 函數的實現方式取決於對象的類型。對於常規對象,它將檢查對象是否在某個根對象 (例如堆棧或全局變量) 中被引用。對於不同類型的對象,例如字符串、函數等,它有不同的實現方式。

總之,gcTestIsReachable 函數是垃圾回收器中的重要組成部分,用於確定哪些對象需要保留在堆中,哪些對象可以被垃圾回收器清理。

gcTestPointerClass

在 Go 語言中,垃圾回收是非常重要的一個功能,負責回收不再使用的內存,避免內存泄漏等問題。在 Go 語言中,垃圾回收是通過掃描內存中的指針來實現的,而 GC 中的指針分類就是根據指針的類型進行分類,以便於 GC 可以更好地識別和回收內存。

在 Go 語言的 runtime/mgc.go 文件中,gcTestPointerClass 函數是用於測試一個指針所屬的指針類別的函數。一個指針的指針類別決定了 GC 如何掃描它,以及垃圾回收期間是否可能需要複製它指向的對象。gcTestPointerClass 函數使用一個特殊的標記位來確定指針的類型,判斷該指針是否是指向堆對象的指針,從而將該指針標記爲有效的指針,避免垃圾回收誤刪除該指針引用的對象。此外,gcTestPointerClass 函數還通過檢查指針所處的頁的狀態來確定該指針指向的對象是否在當前的堆頁中,從而幫助垃圾回收器回收該對象。

總之,gcTestPointerClass 函數在 Go 語言的垃圾回收中起到非常重要的作用,它幫助 GC 識別和管理指針,以確保內存的正確回收和利用。

內容由 chatgpt 生成,倉庫地址:https://github.com/cuishuang/explain-source-code-by-chatgpt

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/oUhgI0Ra-DomCMAOCjfQDw