Go GC 重大改進(jìn):Green Tea 性能提升 10-40%!
最近 Go 1.25 發(fā)布了一個(gè)讓人眼前一亮的新特性——Green Tea 垃圾回收器。
據(jù)說 Google 內(nèi)部已經(jīng)在生產(chǎn)環(huán)境大規(guī)模使用了,GC 時(shí)間直接降低了 10%左右,有些場景甚至能減少 40%。
今天我們就來好好聊聊這個(gè) Green Tea 到底是什么東西,為什么能有這么大的性能提升。
背景
Go GC 階段介紹
Go 的垃圾回收器用的是標(biāo)記-清除(mark-sweep)算法。這個(gè)算法本身不復(fù)雜,核心就是兩個(gè)階段:
1、標(biāo)記階段:從根對象(全局變量、局部變量)開始,沿著指針一路追蹤,把能訪問到的對象都標(biāo)記為"訪問過"。這就像圖的遍歷一樣,深度優(yōu)先或廣度優(yōu)先都行。
2、清除階段:把沒標(biāo)記到的對象清理掉,釋放內(nèi)存。
Go 程序花在垃圾回收上的 CPU 時(shí)間其實(shí)挺多的。不少程序要花 20% 甚至更多的 CPU 時(shí)間在 GC 上,這個(gè)開銷確實(shí)有點(diǎn)大。
“問題” 出在標(biāo)記階段。
標(biāo)記階段的性能瓶頸
從多年的性能分析來看,Go 團(tuán)隊(duì)發(fā)現(xiàn)了兩個(gè)關(guān)鍵問題:
1、GC 大約 90%的時(shí)間都花在標(biāo)記上,只有 10%在清除。清除已經(jīng)優(yōu)化得很好了,但標(biāo)記這塊還有很大空間。
2、標(biāo)記時(shí)間里,至少 35%的時(shí)間是在等內(nèi)存訪問。這個(gè)問題更要命,因?yàn)樗鼤?huì)讓現(xiàn)代 CPU 的各種優(yōu)化手段都失效。
為什么標(biāo)記階段這么慢?
問題的根源在于內(nèi)存訪問模式。我們來看個(gè)例子:

這是一個(gè)簡單的堆內(nèi)存示意圖。左邊是根對象(全局變量 x 和 y),右邊是堆上的對象。每個(gè)矩形代表一個(gè)對象,對象之間用指針連接。
傳統(tǒng)的標(biāo)記算法是怎么工作的呢?我們來跟著它走一遍:

從根對象開始,沿著指針一個(gè)個(gè)遍歷...

最后把所有可達(dá)對象都標(biāo)記完成。
看起來挺正常的,但關(guān)鍵問題是訪問路徑:

注意到?jīng)]有?GC 在內(nèi)存里跳來跳去,做一點(diǎn)點(diǎn)工作就跳到另一個(gè)地方。這就像在城市街道開車,到處都是紅綠燈和轉(zhuǎn)角,根本跑不起來。
CPU 的痛苦
現(xiàn)代 CPU 有很多緩存優(yōu)化。訪問緩存里的數(shù)據(jù)可能只要 1-2 個(gè)時(shí)鐘周期,但訪問主內(nèi)存可能要 100 個(gè)周期!CPU 會(huì)自動(dòng)把最近訪問過的數(shù)據(jù)和附近的數(shù)據(jù)加載到緩存。
可是傳統(tǒng)的標(biāo)記算法完全不管這些。兩個(gè)有指針關(guān)系的對象,在內(nèi)存里可能隔得十萬八千里。CPU 的緩存就白費(fèi)了,每次都要等內(nèi)存訪問。
更糟糕的是,這個(gè)問題還在變得越來越嚴(yán)重:
- NUMA 架構(gòu):現(xiàn)在內(nèi)存往往綁定在特定的 CPU 核心上,跨核心訪問更慢了
- 內(nèi)存帶寬下降:CPU 核心越來越多,但每個(gè)核心能用的內(nèi)存帶寬反而下降了
- 并行化瓶頸:雖然 Go 的 GC 是并行執(zhí)行的,但多核之間共享工作隊(duì)列會(huì)產(chǎn)生競爭
Green Tea 的核心思想
那怎么解決這個(gè)問題呢?Go 團(tuán)隊(duì)提出了一個(gè)看似簡單,但極其巧妙的想法:
以頁(page)為單位工作,而不是以對象為單位
聽起來很簡單對吧?但要讓這個(gè)想法真正落地,需要解決很多技術(shù)細(xì)節(jié)。
具體來說:
- 不再掃描單個(gè)對象,而是掃描整個(gè)頁
- 工作列表里存的不是對象,而是頁
- 雖然最終還是要標(biāo)記對象,但元數(shù)據(jù)是按頁組織的
什么是頁?
在 Go 的內(nèi)存管理中,頁(page)是一個(gè) 8KB 的連續(xù)內(nèi)存塊。
同一個(gè)頁里的對象大小都是一樣的。這是 Go 堆內(nèi)存的基本組織單位。

看這張圖,A、B、C、D 都是不同的頁。每個(gè)頁里包含若干個(gè)相同大小的對象槽位。
Green Tea 怎么工作?
我們還是用剛才那個(gè)例子,但這次用 Green Tea 來標(biāo)記。

注意到了嗎?現(xiàn)在每個(gè)對象有兩個(gè) bit 的元數(shù)據(jù):
- seen bit:表示是否見過這個(gè)對象的指針
- scanned bit:表示是否掃描過這個(gè)對象
為什么需要兩個(gè) bit?因?yàn)?Green Tea 的工作列表存的是頁,不是對象。我們需要額外記錄一個(gè)頁里哪些對象已經(jīng)掃描過了。

從根對象出發(fā),發(fā)現(xiàn)了一個(gè)對象,但這次我們把整個(gè)頁 A 加入工作列表,而不是單個(gè)對象。

同樣,第二個(gè)根對象指向的對象在頁 C,我們把頁 C 加入工作列表。

現(xiàn)在開始處理工作列表。取出頁 A,掃描它上面的對象,發(fā)現(xiàn)指向頁 B 的指針,就把頁 B 加入工作列表。
關(guān)鍵點(diǎn)來了!

當(dāng)我們處理頁 B 的時(shí)候,發(fā)現(xiàn)它上面累積了兩個(gè)對象需要掃描。我們可以連續(xù)掃描這兩個(gè)對象,它們在內(nèi)存里是相鄰的!
這就是 Green Tea 的魔法所在。通過以頁為單位工作,我們可以讓對象在頁上累積,然后一次性掃描多個(gè)相鄰的對象。

最后掃描完成,清除不可達(dá)的對象。
路徑對比
我們來對比一下兩種算法的訪問路徑:
傳統(tǒng)算法:
需要 7 次獨(dú)立的掃描操作,到處跳來跳去。
Green Tea:
只需要 4 次掃描,而且每次掃描的范圍更大,訪問的內(nèi)存更連續(xù)!
這就像終于從城市街道開到了高速公路上。CPU 可以充分利用緩存,減少主內(nèi)存訪問,整個(gè)流程順暢多了。
更進(jìn)一步:向量化加速
Green Tea 還有個(gè)殺手锏——利用 AVX-512 向量指令加速。
傳統(tǒng)的圖遍歷算法沒法用向量指令,因?yàn)槊看翁幚淼膶ο蟠笮《疾灰粯樱瑳]有規(guī)律性。但 Green Tea 不一樣,同一個(gè)頁里的對象大小都是固定的,元數(shù)據(jù)的位置也是固定的。
現(xiàn)代 x86 CPU 支持 AVX-512 指令集,有 512 位寬的向量寄存器。一個(gè)頁的所有元數(shù)據(jù)可以放在兩個(gè)寄存器里,用幾條指令就能處理完一整個(gè)頁!
向量化掃描流程
簡單來說,這個(gè)流程是這樣的:
- 加載元數(shù)據(jù):把頁的 seen 和 scanned 位都加載到向量寄存器
- 計(jì)算差異:用位運(yùn)算找出哪些對象需要掃描
- 展開位圖:把"每個(gè)對象一個(gè) bit"展開成"每 8 字節(jié)一個(gè) bit"
- 找出指針:和頁的指針/標(biāo)量位圖做交集,定位所有指針的位置
- 批量處理:用向量指令一次處理 64 字節(jié)的數(shù)據(jù)
這里有個(gè)很酷的指令VGF2P8AFFINEQB,它可以高效地做位圖展開操作。
這是 Intel Ice Lake 和 AMD Zen 4 引入的新指令,專門用來做 bit 級別的矩陣變換。
有了向量化,掃描速度可以再提升 10% 左右。
性能表現(xiàn)
那么 Green Tea 到底有多快?
在 Go 團(tuán)隊(duì)的基準(zhǔn)測試中:GC 的 CPU 開銷普遍降低 10%-40%。
也就是如果一個(gè)程序本來花 10%的時(shí)間在 GC 上,那么 Green Tea 可以讓總體 CPU 使用率降低 1%-4%。
Google 內(nèi)部已經(jīng)大規(guī)模部署了 Green Tea,看到了類似的性能提升。
當(dāng)然也不是所有場景都能受益。Green Tea 的效果取決于能否在頁上累積足夠多的對象。
如果一個(gè)頁每次只能掃描一個(gè)對象,那可能反而會(huì)有輕微的性能損失。
不過好消息是,實(shí)踐中發(fā)現(xiàn)只要每次能掃描頁面 2% 的內(nèi)容,就能比傳統(tǒng)算法快。這個(gè)門檻其實(shí)挺低的。
如何使用
Go 1.25 已經(jīng)包含了 Green Tea,但默認(rèn)不開啟。你可以通過環(huán)境變量啟用它:
GOEXPERIMENT=greenteagc go buildGo 團(tuán)隊(duì)計(jì)劃在Go 1.26 把 Green Tea 設(shè)為默認(rèn),不過你還是可以選擇退出:
GOEXPERIMENT=nogreenteagc go buildGo 1.26 還會(huì)加入前面提到的向量化優(yōu)化,以及基于反饋?zhàn)龅母鞣N改進(jìn)。
背后的故事
Green Tea 看起來是個(gè)簡單的想法,但實(shí)際上是多年探索的結(jié)晶。
這個(gè)想法的種子早在 2018 年就埋下了。Go 團(tuán)隊(duì)的 Michael Pratt、Cherry Mui、David Chase、Keith Randall 等人都貢獻(xiàn)了關(guān)鍵想法。Intel 的 Yves Vandriessche 提供了微架構(gòu)層面的洞察。

Green Tea 這個(gè)名字是 2024 年 Austin 在日本咖啡店巡游時(shí)想出來的,當(dāng)時(shí)他喝了很多抹茶,同時(shí)在做原型驗(yàn)證。
到 2025 年,Michael 把 Green Tea 完整實(shí)現(xiàn)并投入生產(chǎn)。這期間想法還在不斷演化和改進(jìn)。
總結(jié)
Green Tea 通過以頁為單位組織 GC 工作,顯著改善了內(nèi)存訪問模式,讓 CPU 可以更好地利用緩存,減少主內(nèi)存訪問。再加上向量化加速,性能提升相當(dāng)可觀。
這個(gè)改進(jìn)對 Go 生態(tài)意義重大。畢竟 GC 性能一直是 Go 被詬病的點(diǎn)之一。現(xiàn)在有了 Green Tea,Go 程序的整體性能又能上一個(gè)臺(tái)階。
Go 1.25 已經(jīng)可以體驗(yàn)了,Go 1.26 就會(huì)默認(rèn)啟用。強(qiáng)烈建議大家試試看。




























