GC 與 mutator 線程并發(fā)運行,允許多個 GC 線程并行運行
創(chuàng)新互聯(lián)從2013年成立,先為鳳山等服務建站,鳳山等地企業(yè),進行企業(yè)商務咨詢服務。為鳳山企業(yè)網站制作PC+手機+微官網三網同步一站式服務解決您的所有建站問題。
GC 是一個使用寫屏障的并發(fā)標記和清除。
GC 是非分代的,非緊湊的。
Allocation 是按照大小隔離每個 P 分配的區(qū)域來完成的,以在消除常見情況下的鎖的同時,最小化碎片。
了解 GC 的好地方,可以從 Richard Jones 的 gchandbook.org 開始。
1. GC 執(zhí)行清除終止
? a. Stop the world ,這將導致所有 P 達到 GC 安全點。
? b. 清除任何未清除過的 spans ,只有在預期時間之前強制執(zhí)行此 GC 周期時,才會有未清除的 span 。
2. GC 執(zhí)行標記階段
? a.?? 準備標記階段,將 gcphase 設置為 _GCmark (從 _GCoff 開始),啟用寫屏障,啟用 mutator assist ,并對根標記作業(yè)進行排隊。
在所有 P 都啟用寫屏障之前,不會掃描任何對象,這是使用 STW 完成的。
? ?b. Start the world ,從現(xiàn)在開始,GC 工作由調度器啟動的 標記worker 和作 為 allocation 的一部分執(zhí)行的 assists 來完成。
寫屏障將覆寫的指針和任何指針寫的新指針值都著色。
新分配的對象立即被標記為黑色。
? c.?? GC 執(zhí)行根標記作業(yè)。包括: 掃描所有棧 , 著色所有全局變量 ,以及 著色堆外運行時數(shù)據(jù)結構中的任何堆指針 。
掃描棧會停止goroutine,對goroutine棧中找到的任何指針進行著色,然后恢復goroutine。
? ? d.?? GC 耗盡灰色對象的工作隊列,將每個 灰色 對象掃描為 黑色 ,并對在該對象中找到的所有指針進行著色(反過來可能會將這些指針添加到工作隊列中)。
? ?e.?? 由于 GC work 分散在本地緩存中,因此 GC 使用 分布式終止算法 來檢測何時不再有根標記作業(yè)或灰色對象(參見 gcMarkDone 函數(shù))。
此時,GC 狀態(tài)轉換到標記終止( gcMarkTermination )。
3. GC 執(zhí)行標記終止 gcMarkTermination
? a. Stop the world
? b. 將 gcphase 設置為 _GCmarktermination ,并禁用 workers 和 assists。
? c. 進行內務整理,如 flushing mcaches
4. GC 執(zhí)行清除階段
? ?a. 準備清除階段,將 gcphase 設置為 _GCoff ,設置清除狀態(tài)并禁用寫屏障。
? b. Start the world ,從現(xiàn)在開始,新分配的對象是白色的,如有必要,在使用 spans 前 allocating 清除 spans 。
? ?c. GC 在后臺進行 并發(fā)清除 并響應 allocation ,見下面的描述。
5. 當分配足夠時,重復上面 1 開始的步驟,參見下面關于 GC rate 的討論。
清除階段與正常程序執(zhí)行并發(fā)進行。
在后臺 goroutine 中,堆被惰性(當 goroutine 需要另一個 span 時)且并發(fā)地逐個 span 掃描(這有助于不是 CPU bound 的程序)。
在 STW 標記終止 的結尾,所有的 span 都被標記為 需要清除 。
后臺清除器 goroutine 簡單地逐個清除 span 。
為了避免在存在未清除的 span 時請求更多的 OS內存 ,當 goroutine 需要另一個 span 時,它首先嘗試通過清除來回收這些內存。
當 goroutine 需要分配一個新的 小對象span 時,它會清除相同大小的小對象 span ,直到釋放至少一個對象為止。
當 goroutine 需要從堆中分配 大對象span 時,它會清除 span ,直到將至少那么多頁面釋放到堆中。
有一種情況,這可能是不夠的:如果 goroutine 清除并釋放兩個不相鄰的 單頁span 到堆中,那么它將分配一個新的 雙頁span ,但是仍然可以有其他 單頁未清除的span ,可以組合成 雙頁的span 。
確保在未清除的 span 上不進行任何操作(這會破壞 GC 位圖中的標記位)至關重要。
在 GC 期間,所有 mcache 都被刷新到 中央緩存 中,因此它們是空的。
當一個 goroutine 抓取一個新的 span 到 mcache 時, goroutine 會清除 mcache 。
當 goroutine 顯式釋放對象或設置 finalizer 時,goroutine 確保 span 已經清除(通過清除或者等待并發(fā)清除完成)。
finalizer goroutine 僅在所有 span 已經清除時才開始。
當下一次 GC 啟動時,它將清除所有尚未清除的 span (如果有的話)。
下一次 GC 是在我們分配了與已經使用的內存成正比的額外內存量之后。
該比例由 GOGC 環(huán)境變量控制(默認為 100 )。
如果 GOGC=100 ,而我們使用的是 4M ,那么當達到 8M 時,我們將再次進行 GC(此標記在 next_gc 變量中被跟蹤)。
獲取 GOGC :
這使得 GC成本 與 allocation 成本 成線性比例。
調整 GOGC 只會改變線性常量(以及使用的額外內存量)。
為了防止在掃描大型對象時出現(xiàn)長時間的暫停,并提高并行性,垃圾收集器將大于 maxObletBytes 的對象的掃描作業(yè)分解為最多 maxObletBytes 的 oblets 。
當掃描遇到大對象時,它只掃描第一個 oblet ,并將其余 oblets 作為新的掃描作業(yè)排隊。
最近在看左神新書 《Go 語言設計與實現(xiàn)》的垃圾收集器時產生一個疑惑,花了點時間搞清楚了記錄一下。
Go 語言垃圾回收的實現(xiàn)使用了標記清除算法,將對象的狀態(tài)抽象成黑色(活躍對象)、灰色(活躍對象中間狀態(tài))、白色(潛在垃圾對象也是所有對象的默認狀態(tài))三種,注意沒有具體的字段標記顏色。
整個標記過程就是把白色對象標黑的過程:
1.首先將 ROOT 根對象(包括全局變量、goroutine 棧上的對象等)放入到灰色集合
2.選一個灰色對象,標成黑色,將所有可達的子對象放入到灰色集合
3.重復2的步驟,直到灰色集合中為空
下圖是書上的插圖,看上去是一個典型的深度優(yōu)先搜索的算法。
下圖是劉丹冰寫的《Golang 修養(yǎng)之路》的插圖,看上去是一個典型的廣度優(yōu)先搜索的算法。
我疑惑的點在于這個標記過程是深度優(yōu)先算法還是廣度優(yōu)先算法,因為很多文章博客對此都沒有很清楚的說明,作為學習者這種細節(jié)其實也不影響對整個 GC 流程的理解,但是這種細節(jié)我非常喜歡扣:)
對著書和源碼摸索著大致找到了一個結果是深度優(yōu)先。下面看下大致的過程,源碼基于1.15.2版本:
gcStart 是 Go 語言三種條件觸發(fā) GC 的共同入口
啟動后臺標記任務
為每個處理器創(chuàng)建用于執(zhí)行后臺標記任務的 Goroutine
上面休眠的 G 會在調度循環(huán)中檢查并喚醒執(zhí)行
執(zhí)行標記
gcw 是每個 P 獨有的所以不用擔心并發(fā)的問題 和 GMP、mcache 一樣設計,減少鎖競爭
嘗試在全局列表中獲取一個不為空的 buf
這是官方實現(xiàn)的無鎖隊列:)漲見識了,for 循環(huán)加原子操作實現(xiàn)棧的 pop
到這里從灰色集合中獲取待掃描的對象邏輯說完了。找到對象了接著就是 scanobject(b, gcw) 了,里面有兩段邏輯要注意
根據(jù)索引位置找到對象進行標色
嘗試存入 gcwork 的緩存中,或全局隊列中
無鎖隊列,for 循環(huán)加原子操作實現(xiàn)棧的 push
到這里把灰色對象標黑就完成了,又放回灰色集合接著掃下一個指針。
Go 語言設計與實現(xiàn) 垃圾收集器
Golang三色標記+混合寫屏障GC模式全分析
從Gov1.12版本開始,Go使用了非分代的、并發(fā)的、基于三色標記清除的垃圾回收器。
關于垃圾回收,比較常見的算法有引用計數(shù)、標記清除和分代收集,Golang語言使用的垃圾回收算法是標記清除。
Golang語言的標記清除垃圾回收算法,為了防止GC掃描時內存變化引起的混亂。那么就需要 STW,即Stop The World。具體在Golang語言中是指,在GC時先停止所有goroutine。再進行垃圾回收,等待垃圾回收結束后再恢復所有被停止的goroutine。
標記清除方法
啟動STW,暫停程序的業(yè)務邏輯,找出不可達對象和可達對象。
將所有可達對象做標記,清除未標記的對象。停止STW,程序繼續(xù)執(zhí)行。循環(huán)往復,直到進程程序生命周期結束。因為STW需要暫停程序,為了減少暫停程序的時間。將清除操作移出 STW執(zhí)行周期,但是優(yōu)化效果不明顯。
所謂三色標記,實際上只是為了方便敘述而抽象出來的一種說法,三色對應垃圾回收過程中對象的三種狀態(tài)。白色是對象未被標記,gcmarkBits對應位為0,該對象將會在本次GC中被清理。灰色是對象還在標記隊列中等待被標記,黑色是對象已被標記,gcmarkBits對應位為0,該對象將會在本次 GC中被回收。
網頁名稱:go語言gc狀態(tài)收集 go的gc對比java 的gc
路徑分享:http://chinadenli.net/article8/dodoiip.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供動態(tài)網站、企業(yè)建站、做網站、網站建設、服務器托管、關鍵詞優(yōu)化
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)