一文掌握垃圾回收:原理、算法與高性能 GC 優(yōu)化
在面試過(guò)程中,垃圾回收算法經(jīng)常會(huì)被問(wèn)到,本文就來(lái)分享下常見(jiàn)的垃圾回收算法及其優(yōu)缺點(diǎn),以幫助你在面試過(guò)程中更好的應(yīng)對(duì)這些面試問(wèn)題。

一、GC 入門:GC 基礎(chǔ)概念
垃圾回收(Garbage Collection,GC) 是一種自動(dòng)內(nèi)存管理機(jī)制。當(dāng)程序申請(qǐng)的堆內(nèi)存不再被使用時(shí),GC 會(huì)主動(dòng)將這些內(nèi)存回收,以供后續(xù)分配或返還給操作系統(tǒng)。
1. 內(nèi)存管理三大參與者
在程序進(jìn)行 GC 時(shí),有以下 3 個(gè)參與者參與到了 GC 的過(guò)程中:
- Mutator(用戶程序)
 - Allocator(內(nèi)存分配器)
 - Collector(垃圾回收器)
 

上圖是內(nèi)存管理的三個(gè)參與者,Mutator 用戶程序、Allocator 內(nèi)存分配器和 Collector 垃圾回收。用戶程序 Mutator 會(huì)通過(guò)內(nèi)存分配器 Allocator 去申請(qǐng)內(nèi)存 Memory,而垃圾回收器 Collector 則會(huì)回收無(wú)用的堆內(nèi)存。
2. GC 核心優(yōu)勢(shì)與劣勢(shì)
使用 GC 會(huì)給開(kāi)發(fā)者帶來(lái)很多好處,以下是 GC 的核心優(yōu)勢(shì):
- 開(kāi)發(fā)者無(wú)需手動(dòng)管理內(nèi)存,降低心智負(fù)擔(dān);
 - 自動(dòng)釋放殘留內(nèi)存,減少內(nèi)存泄漏風(fēng)險(xiǎn);
 - 可通過(guò)調(diào)控 API(如觸發(fā)時(shí)機(jī)、暫停策略)進(jìn)行優(yōu)化。
 
使用 GC 通常也會(huì)帶來(lái)以下劣勢(shì):
- 暫停(Stop-The-World,STW)可能影響實(shí)時(shí)性
 - 性能開(kāi)銷與程序吞吐率相關(guān)
 
3. 不同語(yǔ)言內(nèi)存管理策略對(duì)比
不同編程語(yǔ)言采用的內(nèi)存管理策略是不一樣的,下表是常見(jiàn)內(nèi)存管理策略比較:
方式  | 代表語(yǔ)言  | 特點(diǎn)  | 缺點(diǎn)  | 
手動(dòng)管理  | C/C++  | 性能高、可控性強(qiáng)  | 易出錯(cuò)(內(nèi)存泄漏、懸掛指針)  | 
自動(dòng)管理  | Java、Go  | 開(kāi)發(fā)者無(wú)需釋放,安全性好  | 暫停、性能開(kāi)銷  | 
所有權(quán)機(jī)制  | Rust  | 編譯期安全、無(wú)運(yùn)行時(shí) GC  | 學(xué)習(xí)曲線陡峭  | 
二、能否回收:基礎(chǔ)垃圾識(shí)別算法
對(duì)堆垃圾回收前的第一步就是要判斷哪些對(duì)象已經(jīng)死亡(即不能再被任何途徑使用的對(duì)象)。判斷一個(gè)對(duì)象是否存活有引用計(jì)數(shù)、可達(dá)性分析這兩種算法,兩種算法各有優(yōu)缺點(diǎn)。、
Java 和 Go 都使用可達(dá)性分析算法,一些動(dòng)態(tài)腳本語(yǔ)言(如:ActionScript)一般使用引用計(jì)數(shù)算法。
1. 引用計(jì)數(shù)(Reference Counting)
引用計(jì)數(shù)會(huì)為每個(gè)對(duì)象維護(hù)一個(gè)計(jì)數(shù)器,當(dāng)該對(duì)象被其他對(duì)象引用時(shí)加1,引用失效時(shí)減 1,當(dāng)引用次數(shù)為 0 后即可回收對(duì)象。
引用計(jì)數(shù)通過(guò)在對(duì)象上增加自己被引用的次數(shù),被其他對(duì)象引用時(shí)加 1,引用自己的對(duì)象被回收時(shí)減1,引用數(shù)為 0 的對(duì)象即為可以被回收的對(duì)象,這種算法在內(nèi)存比較緊張和實(shí)時(shí)性比較高的系統(tǒng)中使用比較廣泛,如 PHP,Python 等。

優(yōu)點(diǎn):
- 原理和實(shí)現(xiàn)都比較簡(jiǎn)單;
 - 回收及時(shí)性高,引用計(jì)數(shù)為0則立即回收,不需要想其他GC機(jī)制需要等待特定的時(shí)間回收;
 - 不需要暫停應(yīng)用即可完成回收。
 
缺點(diǎn):
- 無(wú)法解決循環(huán)引用的問(wèn)題,例如:a.b=b; b.a=a;
 - 時(shí)間和空間成本高:每個(gè)對(duì)象需要額外的空間來(lái)存儲(chǔ)引用計(jì)數(shù),在棧上修改引用計(jì)數(shù)的時(shí)間成本高(因?yàn)樾枰~外的原子操作來(lái)保證線程安全);
 - 無(wú)法保證耗時(shí):引用計(jì)數(shù)是一種攤銷算法,會(huì)將內(nèi)存的回收分?jǐn)偟秸麄€(gè)程序的運(yùn)行過(guò)程,當(dāng)銷毀一個(gè)很大的樹(shù)形結(jié)構(gòu)時(shí)無(wú)法保證響應(yīng)時(shí)間。
 
2. 可達(dá)性分析(Reachability Analysis)
可達(dá)性分析的核心思想是判斷一個(gè)對(duì)象是否可達(dá),如果這個(gè)對(duì)象一旦不可達(dá)就可以立刻被 GC 回收了,那么我們?cè)趺磁袛嘁粋€(gè)對(duì)象是否可達(dá)呢?第一步,從根節(jié)點(diǎn)開(kāi)始找出所有的全局變量和當(dāng)前函數(shù)棧里的變量,標(biāo)記為可達(dá)。第二步,從已經(jīng)標(biāo)記的數(shù)據(jù)開(kāi)始,進(jìn)一步標(biāo)記它們可訪問(wèn)的變量,以此類推,專業(yè)術(shù)語(yǔ)叫傳遞閉包。當(dāng)追蹤結(jié)束時(shí),沒(méi)有被打上標(biāo)記的對(duì)象就被判定是不可觸達(dá)。

該算法屬于追蹤式算法,目的是回收不可達(dá)對(duì)象,可達(dá)對(duì)象主要包括兩類:
- GC Roots 對(duì)象: 包括全局對(duì)象,棧上對(duì)象;
 - 與 GC Roots 對(duì)象通過(guò)引用鏈相連的對(duì)象。
 
對(duì)于不可達(dá)對(duì)象,我們認(rèn)為該對(duì)象為垃圾對(duì)象,應(yīng)該被回收。
同上述的引用計(jì)數(shù)法相比,追蹤式算法具有如下優(yōu)點(diǎn):
- 解決了循環(huán)引用的問(wèn)題;
 - 占用的空間少了。
 
和引用計(jì)數(shù)法相比,也有以下缺點(diǎn):
- 無(wú)法立刻識(shí)別出垃圾對(duì)象,需要依賴 GC 線程;
 - 算法在標(biāo)記時(shí)必須暫停整個(gè)程序,即 STW(stop the world),否則其他線程有可能會(huì)修改對(duì)象的狀態(tài)從而回收不該被回收的對(duì)象。
 
三、如何回收:基于可達(dá)性分析的 GC 算法
現(xiàn)代主流的 GC 算法都基于可達(dá)性分析,并在此基礎(chǔ)上實(shí)現(xiàn)了不同的回收策略。
1. 標(biāo)記-復(fù)制算法(Copying Collector)
它把內(nèi)存空間劃分為兩個(gè)相等的區(qū)域,每次只使用其中一個(gè)區(qū)域。在垃圾收集時(shí),遍歷當(dāng)前使用的區(qū)域,把存活對(duì)象復(fù)制到另一個(gè)區(qū)域中,最后將當(dāng)前使用的區(qū)域的可回收對(duì)象進(jìn)行回收。
實(shí)現(xiàn)主要分為標(biāo)記和復(fù)制兩個(gè)步驟:
- 標(biāo)記: 記錄需要回收的垃圾對(duì)象;
 - 復(fù)制: 將內(nèi)存分為大小相同的兩塊,當(dāng)某一塊的內(nèi)存使用完了之后就將使用中的對(duì)象挨個(gè)復(fù)制到另一塊內(nèi)存中,最后將當(dāng)前內(nèi)存恢復(fù)為未使用狀態(tài)。
 

優(yōu)點(diǎn):
- 不用進(jìn)行大量垃圾對(duì)象的掃描:標(biāo)記-復(fù)制算法需要從 GC-root 對(duì)象出發(fā),將可達(dá)的對(duì)象復(fù)制到另外一塊內(nèi)存后直接清理當(dāng)前這塊的內(nèi)存即可;
 - 解決了內(nèi)存碎片問(wèn)題,防止分配大空間對(duì)象時(shí)提前 GC 的問(wèn)題。
 
缺點(diǎn):
- 復(fù)制成本問(wèn)題:在可達(dá)對(duì)象占用內(nèi)存高的時(shí)候,復(fù)制成本會(huì)很高;
 - 內(nèi)存利用率低:相當(dāng)于可利用的內(nèi)存僅有一半。
 
2. 標(biāo)記-清除算法(Mark-and-Sweep)
標(biāo)記-清除算法是最常見(jiàn)的垃圾收集算法,標(biāo)記清除收集器是跟蹤式垃圾收集器,其執(zhí)行過(guò)程可以分成標(biāo)記(Mark)和清除(Sweep)兩個(gè)階段:
- 標(biāo)記階段:暫停應(yīng)用程序的執(zhí)行,從根對(duì)象觸發(fā)查找并標(biāo)記堆中所有存活的對(duì)象;
 - 清除階段:遍歷堆中的全部對(duì)象,回收未被標(biāo)記的垃圾對(duì)象并將回收的內(nèi)存加入空閑鏈表,恢復(fù)應(yīng)用程序的執(zhí)行。
 

優(yōu)點(diǎn):
- 實(shí)現(xiàn)簡(jiǎn)單;
 - 算法吞吐量高,即運(yùn)行用戶代碼時(shí)間 /(運(yùn)行用戶代碼時(shí)間+運(yùn)行垃圾收集時(shí)間);
 - 空間利用率高,和標(biāo)記-復(fù)制相比,不需要額外的空間復(fù)制對(duì)象,和引用計(jì)數(shù)法相比,也不需要額外的空間設(shè)置計(jì)數(shù)器
 
缺點(diǎn):
- 執(zhí)行期間需要把整個(gè)程序完全暫停,不能異步的進(jìn)行垃圾回收;
 - 容易產(chǎn)生大量不連續(xù)的內(nèi)存隨便,碎片太多可能會(huì)導(dǎo)致后續(xù)沒(méi)有足夠的連續(xù)內(nèi)存分配給較大的對(duì)象,從而提前觸發(fā)新的一次垃圾收集動(dòng)作。
 
3. 標(biāo)記-整理算法(Mark-and-Compact)
標(biāo)記-整理算法(也叫標(biāo)記-壓縮算法)標(biāo)記出所有可達(dá)對(duì)象,然后將可達(dá)對(duì)象移動(dòng)到空間的另外一段,最后清理掉邊界以外的內(nèi)存。

優(yōu)點(diǎn):
- 避免了內(nèi)存碎片化的問(wèn)題;
 - 適合老年代算法,老年代對(duì)象存活率高的情況下,標(biāo)記整理算法由于不需要復(fù)制對(duì)象,效率更高。
 
缺點(diǎn):整理的過(guò)程復(fù)雜,需要多長(zhǎng)遍歷內(nèi)存,導(dǎo)致 STW 時(shí)間比標(biāo)記清除算法高。
四、性能優(yōu)化:GC 優(yōu)化策略
在解決了“能否回收”和“如何回收”的基礎(chǔ)問(wèn)題后,垃圾回收技術(shù)演進(jìn)的下一個(gè)核心目標(biāo)便是“如何更高效、更低延遲地回收”。
為了應(yīng)對(duì)“Stop-The-World”暫停過(guò)長(zhǎng)這一核心痛點(diǎn),現(xiàn)代垃圾回收器主要從兩個(gè)維度進(jìn)行優(yōu)化:一是通過(guò)分代收集(Generational GC),根據(jù)對(duì)象的生命周期特點(diǎn)“區(qū)別對(duì)待”,從而減少單次回收的工作量。二是通過(guò)增量與并發(fā) GC(Incremental & Concurrent GC),改變回收的執(zhí)行方式,將巨大的暫停拆解或與用戶程序并行,從而最大化地降低對(duì)程序的影響。
1. 分代收集算法(Generational GC)
分代收集算法按照對(duì)象生命周期的長(zhǎng)短劃分到不同分區(qū):
- 對(duì)于生命周期短的新生代區(qū)域(Young),每次回收僅需要考慮如何保留少量存活對(duì)象,因此可以采用標(biāo)記-復(fù)制法完成 GC;
 - 對(duì)于生命周期長(zhǎng)的老年代區(qū)域(Old),可以通過(guò)減少 GC 的頻率來(lái)提供效率,同時(shí)由于對(duì)象存活率高沒(méi)有額外的空間用于復(fù)制,因此一般可以使用標(biāo)記清除法或標(biāo)記整理法。
 

這樣劃分,堆就分成了 Young 和 Old 兩個(gè)分區(qū),因此 GC 也分為新生代 GC 和老年代 GC。
對(duì)象的分配策略:
- 對(duì)象優(yōu)先在新生代上 Eden 區(qū)域分配;
 - 大對(duì)象直接進(jìn)入老年代;
 - 新生代中周期較長(zhǎng)的對(duì)象在 s0 或 s1 區(qū)每經(jīng)過(guò)一次新生代 GC,就增加一歲,增加到一定閾值的時(shí)候,就進(jìn)入老年代區(qū)域。
 
2. 增量與并發(fā) GC
前面提到的傳統(tǒng) GC 算法都會(huì) STW,這存在兩個(gè)嚴(yán)重的弊端:
- 對(duì)實(shí)時(shí)性程序來(lái)說(shuō),很致命;
 - 對(duì)多核計(jì)算機(jī)來(lái)說(shuō),會(huì)造成計(jì)算資源的浪費(fèi)。
 

為了避免一次性完成所有 GC 工作導(dǎo)致的長(zhǎng)時(shí)間 STW,可以將 GC 過(guò)程拆分為多個(gè)小步驟,與用戶程序交替執(zhí)行。
- 增量 GC(Incremental GC):將 GC 工作分成多個(gè)階段,穿插在用戶程序中執(zhí)行,分?jǐn)偭藭和r(shí)間;
 - 并發(fā) GC(Concurrent GC):讓 GC 線程與用戶程序線程在一段時(shí)間內(nèi)同時(shí)運(yùn)行,極大地減少了 STW。
 
這兩種策略都依賴于三色標(biāo)記法和屏障技術(shù)來(lái)保證在并發(fā)環(huán)境下的正確性。
3. 增量 GC(Incremental GC)

分?jǐn)?GC 時(shí)間,避免程序長(zhǎng)時(shí)間暫停;
內(nèi)存屏障技術(shù),需要額外時(shí)間開(kāi)銷,并且由于內(nèi)存屏障技術(shù)的保守性,一些垃圾對(duì)象不會(huì)被回收,會(huì)增加一輪 GC 的總時(shí)長(zhǎng)。
4. 并發(fā) GC(Concurrent GC)

- 運(yùn)行 GC 和用戶程序并行;
 - 一定程度上利用多核計(jì)算機(jī)的優(yōu)勢(shì)減少了對(duì)用戶程序的干擾,不該寫屏障的額外開(kāi)銷和保守性問(wèn)題仍然存在,這是不可避免的。
 
五、并發(fā)保證:三色標(biāo)記與屏障技術(shù)
引入并發(fā) GC 的目的是為了消除或顯著縮短“Stop-The-World”的暫停時(shí)間,但這帶來(lái)了一個(gè)棘手的挑戰(zhàn):當(dāng) GC 線程正在遍歷對(duì)象圖時(shí),用戶線程可能同時(shí)在修改對(duì)象間的引用關(guān)系。這種并發(fā)修改可能導(dǎo)致 GC“看錯(cuò)”對(duì)象的可達(dá)性,從而錯(cuò)誤地回收仍在使用的對(duì)象。
為了保證在并發(fā)環(huán)境下數(shù)據(jù)的一致性和 GC 的正確性,現(xiàn)代垃圾回收器引入了 三色標(biāo)記法(Tri-color Marking)作為核心算法框架,并配合屏障技術(shù)(Barrier)來(lái)追蹤并發(fā)間的引用變化,確保萬(wàn)無(wú)一失。
1. 三色標(biāo)記(Tri-color Marking)
前面的標(biāo)記-X 類算法都有一個(gè)問(wèn)題,那就是 STW(即 GC 時(shí)暫停整個(gè)應(yīng)用程序),三色標(biāo)記法是對(duì)標(biāo)記階段進(jìn)行改進(jìn)的算法。目的是在不暫停程序的情況下即可完成對(duì)象的可達(dá)性分析,GC 線程將所有對(duì)象分為三類:
- 白色對(duì)象:未搜索的對(duì)象(潛在的垃圾),在回收周期開(kāi)始時(shí)所有對(duì)象都是白色,在回收周期結(jié)束時(shí),所有對(duì)象都是垃圾回收對(duì)象;
 - 灰色對(duì)象:正在搜索的對(duì)象(活躍的對(duì)象),但是對(duì)象身上還有一個(gè)或多個(gè)引用沒(méi)有掃描;
 - 黑色對(duì)象:已搜索完成的對(duì)象(活躍的對(duì)象),所有的引用已被掃描完
 
三色標(biāo)記算法屬于增量式 GC 算法,回收器首先將所有對(duì)象著色成白色,然后從 GC Roots 出發(fā),逐步把所有可達(dá)的對(duì)象變成灰色再到黑色,最終所有的白色對(duì)象都是不可達(dá)對(duì)象。
GC Roots 區(qū)域主要是程序運(yùn)行到當(dāng)前時(shí)刻的棧和全局?jǐn)?shù)據(jù)區(qū)域。
具體實(shí)現(xiàn):
- 初始時(shí)所有對(duì)象都是白色的;
 - 從 GC Roots 對(duì)象出發(fā),掃描所有可達(dá)對(duì)象并標(biāo)記為灰色,放入待處理隊(duì)列;
 - 從隊(duì)列取出一個(gè)灰色對(duì)象并標(biāo)記為黑色,將其引用對(duì)象標(biāo)記為灰色,放入隊(duì)列;
 - 重復(fù)上一步驟,直到灰色對(duì)象隊(duì)列為空;
 - 此時(shí)剩下的所有白色對(duì)象都是垃圾對(duì)象。
 
結(jié)合如下動(dòng)圖理解:

可以看出:A、F 為 GC Roots 根直接引用的對(duì)象,E、G、H 對(duì)象為垃圾,需要回收。
優(yōu)點(diǎn):不需要 STW。
缺點(diǎn):
- 如果產(chǎn)生垃圾速度大于回收速度時(shí),可能會(huì)導(dǎo)致程序中垃圾對(duì)象越來(lái)越多而無(wú)法及時(shí)收集;
 - 線程切換和上下文轉(zhuǎn)換的消耗會(huì)使得垃圾回收的總體成本上升,從而降低系統(tǒng)吞吐量。
 
三色標(biāo)記法存在并發(fā)性問(wèn)題:
- 可能會(huì)出現(xiàn)野指針(指向沒(méi)有合法地址的指針),從而造成嚴(yán)重的程序錯(cuò)誤;
 - 漏標(biāo),錯(cuò)誤的回收非垃圾對(duì)象。
 
2. 屏障技術(shù)
屏障技術(shù)是在用戶程序讀取、創(chuàng)建以及更新對(duì)象指針時(shí)執(zhí)行的一段代碼,簡(jiǎn)單來(lái)說(shuō),內(nèi)存屏障是一種能夠保證內(nèi)存操作順序的技術(shù)。根據(jù)操作類型的不同,屏障技術(shù)分為讀屏障和寫屏障兩種。
由于讀屏障需要在讀操作時(shí)加入代碼片段,對(duì)用戶程序的影響較大。因此,Go 語(yǔ)言采用寫屏障來(lái)保證三色不變式,寫屏障技術(shù)包括 Dijkstra 在 1978 年提出插入寫屏障和 Yuasa 在 1990 年提出刪除寫屏障兩種。
Go 語(yǔ)言中使用到的屏障技術(shù)包含以下 3 種:
類型  | 工作原理  | 解決的問(wèn)題  | 缺點(diǎn)  | 
插入寫屏障  | 黑色→白色引用時(shí)標(biāo)記白色為灰  | 強(qiáng)三色不變性  | 棧需 STW 掃描  | 
刪除寫屏障  | 刪除引用時(shí)標(biāo)記白色為灰  | 弱三色不變性  | 回收精度低  | 
混合寫屏障(Go 1.8+)  | 棧對(duì)象全黑+堆寫屏障  | 免S TW 重掃描  | 最佳實(shí)踐方案  | 
3. 插入寫屏障
插入寫屏障的原理是:當(dāng)有黑色對(duì)象 A 指向新對(duì)象 D 時(shí),如果被指向?qū)ο?D 為白色,則將 D 對(duì)象設(shè)置為灰色,它實(shí)現(xiàn)了強(qiáng)三色不變式。

如上圖的標(biāo)記過(guò)程:
- 垃圾收集器將根集合上的 A 對(duì)象標(biāo)記為黑色,并將 A 對(duì)象指向的 B 對(duì)象標(biāo)記成灰色;
 - 用戶程序修改 A 對(duì)象的指針,將原本指向 B 對(duì)象的指針指向 C 對(duì)象,這時(shí),觸發(fā)插入寫屏障將 C 對(duì)象標(biāo)記為灰色;
 - 垃圾收集器依次遍歷其它灰色對(duì)象,標(biāo)記為黑色。
 
插入寫屏障將被添加引用的白色對(duì)象都標(biāo)記為了灰色,這種方法實(shí)現(xiàn)簡(jiǎn)單,但也有明顯的缺點(diǎn):
- 缺點(diǎn)一:未存活的對(duì)象可能需要兩次回收,假設(shè)上述第 2 步到第 3 步之間,A 對(duì)象的指針又從指向 C 改為指向 B,那 C 對(duì)象就是垃圾,應(yīng)該回收。但是此時(shí)灰色的對(duì)象 C 會(huì)被垃圾收集器認(rèn)為是存活的,這些被錯(cuò)誤標(biāo)記的對(duì)象只有在下一個(gè)循環(huán)才會(huì)被回收;
 - 缺點(diǎn)二:寫屏障只會(huì)對(duì)堆上的內(nèi)存對(duì)象啟動(dòng)寫屏障(插入和刪除寫屏障共有的)。而棧上的對(duì)象需要保證內(nèi)存安全時(shí),必須在標(biāo)記階段重新對(duì)棧上的對(duì)象進(jìn)行 STW 掃描。重新掃描時(shí)需要暫停程序,影響整體性能。
 
4. 刪除寫屏障
刪除寫屏障的原理是:對(duì)象 A 被引用時(shí),如果引用它的對(duì)象被刪除了,那么白色的 A 對(duì)象將被標(biāo)記為灰色,它實(shí)現(xiàn)了弱三色不變式。

如上圖的標(biāo)記過(guò)程:
- 垃圾收集器將根集合上的 A 對(duì)象標(biāo)記為黑色,并將 A 對(duì)象指向的 B 對(duì)象標(biāo)記成灰色;
 - 用戶程序?qū)?A 指向 B 對(duì)象的指針,修改為指向 C 對(duì)象。這時(shí),觸發(fā)刪除寫屏障,但因?yàn)?B 對(duì)象不為白色,所以不做改變;
 - 用戶程序?qū)?B 指向 C 對(duì)象的指針刪除,觸發(fā)刪除寫屏障,此時(shí),白色的 C 對(duì)象被標(biāo)記為灰色;
 - 垃圾收集器依次遍歷程序中的灰色對(duì)象,將它們標(biāo)記為黑色。
 
刪除寫屏障將被刪除引用的白色對(duì)象都標(biāo)記為了灰色,但是它也有缺點(diǎn)和局限性:
- 缺點(diǎn)一:回收精度低,當(dāng)對(duì)象 B 已經(jīng)被刪除時(shí),它仍然可以活過(guò)這一輪在下一個(gè)循環(huán)才被回收;
 - 缺點(diǎn)二:同插入寫屏障,重新 STW 掃描棧對(duì)象。
 
5. 混合寫屏障(Go 1.8+)
傳統(tǒng)的寫屏障在處理?xiàng)?nèi)存時(shí)仍需短暫的 STW 進(jìn)行重新掃描。Go 語(yǔ)言的混合寫屏障結(jié)合了插入和刪除寫屏障的優(yōu)點(diǎn),并進(jìn)行了優(yōu)化:
(1) GC 開(kāi)始時(shí),將棧上所有可達(dá)對(duì)象標(biāo)記為黑色,無(wú)需 STW 重掃描。
(2) GC 期間,棧上創(chuàng)建的新對(duì)象均為黑色。
(3) 對(duì)堆上的指針操作,同時(shí)啟用插入和刪除寫屏障的邏輯:
- 將被刪除引用的對(duì)象標(biāo)記為灰色;
 - 將被添加引用的對(duì)象標(biāo)記為灰色。
 
這種方式幾乎消除了 STW 的重掃描階段,使得 Go 的 GC 暫停時(shí)間達(dá)到亞毫秒級(jí)別。
六、總結(jié)
本文回顧了各類垃圾回收算法的原理與演進(jìn)后,GC 技術(shù)可以分為兩大模塊:
- 判定可回收對(duì)象:引用計(jì)數(shù) vs. 可達(dá)性分析
 - 執(zhí)行回收策略:標(biāo)記-復(fù)制、標(biāo)記-清除、標(biāo)記-整理 + 并發(fā)/增量調(diào)度
 
分代收集、三色標(biāo)記與屏障技術(shù)是現(xiàn)代高性能 GC 的核心。面試中應(yīng)熟練掌握各方案的原理、優(yōu)缺點(diǎn)與適用場(chǎng)景,并能結(jié)合具體語(yǔ)言(如 Java、Go)的實(shí)現(xiàn)細(xì)節(jié)進(jìn)行答題。















 
 
 












 
 
 
 