垃圾回收GC的全拼是 Garbage Collection 其在維基百科的定義是: 在計算機科學(xué)中,垃圾回收(英語:Garbage Collection,縮寫為GC)是一種自動的內(nèi)存管理機制。當(dāng)一個電腦上的動態(tài)內(nèi)存不再需要時,就應(yīng)該予以釋放,以讓出內(nèi)存,這種內(nèi)存資源管理,稱為垃圾回收(garbage collection)
垃圾回收算法有多種,先看看幾個評價垃圾回收算法性能的幾個方面,再具體看看各種算法的優(yōu)缺點
- 吞吐量 throughput
- 最大暫停時間
- 堆使用效率
- 訪問的局部性
一、 標(biāo)記-清除算法 Mark-Sweep GC
如字面意思 mark-sweep 分為兩個階段:
- 標(biāo)記階段:從根集合出發(fā),將所有活動對象及其子對象打上標(biāo)記
-
清除階段:遍歷堆,將非活動對象(未打上標(biāo)記)的連接到空閑鏈表上
標(biāo)記-清除算法
優(yōu)點
實現(xiàn)簡單, 容易和其他算法組合
缺點
- 碎片化, 會導(dǎo)致無數(shù)小分塊散落在堆的各處
- 分配速度不理想,每次分配都需要遍歷空閑列表找到足夠大的分塊
- 與寫時復(fù)制技術(shù)不兼容,因為每次都會在活動對象上打上標(biāo)記
二、標(biāo)記-壓縮 Mark-Compact
和“標(biāo)記-清除”相似,不過在標(biāo)記階段后它將所有活動對象緊密的排在堆的一側(cè)(壓縮),消除了內(nèi)存碎片, 不過壓縮是需要花費計算成本的。如下圖過程,標(biāo)記后需要定位各個活動對象的新內(nèi)存地址,然后再移動對象,總共搜索了3次堆。

優(yōu)點
有效利用了堆,不會出現(xiàn)內(nèi)存碎片 也不會像復(fù)制算法那樣只能利用堆的一部分
缺點
壓縮過程的開銷,需要多次搜索堆
三、引用計數(shù) Reference Counting
引用計數(shù),就是記錄每個對象被引用的次數(shù),每次新建對象、賦值引用和刪除引用的同時更新計數(shù)器,如果計數(shù)器值為0則直接回收內(nèi)存。 很明顯,引用計數(shù)最大的優(yōu)勢是暫停時間短
優(yōu)點
- 可即刻回收垃圾
- 最大暫停時間短
- 沒有必要沿指針查找, 不要和標(biāo)記-清除算法一樣沿著根集合開始查找
缺點
- 計數(shù)器的增減處理繁重
- 計數(shù)器需要占用很多位
- 實現(xiàn)繁瑣復(fù)雜, 每個賦值操作都得替換成引用更新操作
- 循環(huán)引用無法回收
四、 GC 復(fù)制算法
將堆分為兩個大小相同的空間 From 和 To, 利用 From 空間進行分配,當(dāng) From 空間滿的時候,GC將其中的活動對象復(fù)制到 To 空間,之后將兩個空間互換即完成GC。

優(yōu)點
- 優(yōu)秀的吞吐量, 只需要關(guān)心活動對象
- 可實現(xiàn)高速分配; 因為分塊是連續(xù)的,不需要使用空閑鏈表
- 不會發(fā)生碎片化
- 與緩存兼容
缺點
- 堆使用率低
- 與保守式GC不兼容
- 遞歸調(diào)用函數(shù), 復(fù)制子對象需要遞歸調(diào)用復(fù)制函數(shù) 消耗棧
五、 保守式GC
根空間有以下幾種:
- 寄存器
- 調(diào)用棧
- 全局變量空間
但這些都是不明確的根, 因為調(diào)用棧里邊的調(diào)用幀(call frame) 既有指針也有非指針(值類型)
保守式GC檢查不明確根的基本項目:
- 是不是被正確對齊的值?(在32位cpu的情況下,為4的倍數(shù))
- 是不是指針堆內(nèi)?
- 是不是指著對象的開頭?
有種情況是,非指正和堆里的對象地址一樣;這時保守式GC “把可以的東西看做指針,穩(wěn)妥處理”
保守式GC優(yōu)點:GC不依賴于語言處理程序
缺點:
- 識別指針和非指針需要成本
- 錯誤識別指針會壓迫堆; 可能錯將非指針當(dāng)做指針,然后將其作為內(nèi)存地址使得對應(yīng)堆中的死對象當(dāng)做活對象
- 能夠使用的gc算法有限; 不能使用復(fù)制算法這類移動對象的gc算法
準(zhǔn)確式GC
需要依賴 “語言處理程序的支援”,能基于能精確識別指針和非指針的“正確根”來執(zhí)行g(shù)c
六、分代回收
出發(fā)點:大部分對象生成后馬上就變成垃圾,很少有對象能活的很久
- 新生代 = 生成空間 + 2 * 幸存區(qū) 復(fù)制算法
- 老年代 標(biāo)記-清除算法
對象在生成空間創(chuàng)建,當(dāng)生成空間滿之后進行 minor gc,將活動對象復(fù)制到第一個幸存區(qū),并增加其“年齡” age,當(dāng)這個幸存區(qū)滿之后再將此次生成空間和這個幸存區(qū)的活動對象復(fù)制到另一個幸存區(qū),如此反復(fù),當(dāng)活動對象的 age 達到一定次數(shù)后將其移動到老年代; 當(dāng)老年代滿的時候就用標(biāo)記-清除或標(biāo)記-壓縮算法進行major gc
吞吐量得到改善, 分代垃圾回收花費的時間是GC復(fù)制算法的四分之一;但是如果部分程序新生成對象存活很久的話分代回收會適得其反
七、增量式GC
本來gc只是默默的在幕后回收資源的,但是如果gc任務(wù)繁重則會長時間暫停應(yīng)用程序的執(zhí)行, 增量式gc就是一種逐漸推進垃圾回收來控制mutator最大暫停時間的方法
三色標(biāo)記算法
- 白色: 還未搜索過的對象
- 灰色: 正在搜索的對象
- 黑色: 搜索完成的對象
根查找階段: 對能直接從根引用的對象打上標(biāo)記,堆放到標(biāo)記棧里(白色 涂成 灰色)
標(biāo)記階段: 從標(biāo)記棧中取出對象,將其子對象涂成灰色;這個階段不是一下子處理所有的灰色對象,而只是處理一定個數(shù),然后暫停gc
清除階段: 將沒被標(biāo)記的白色對象連接到空閑鏈表,并重置已標(biāo)記的對象標(biāo)記位
優(yōu)點: 縮短最大暫停時間
缺點: 降低了吞吐量
resources:
維基百科 - 垃圾回收
深入理解java垃圾回收機制
聊聊JVM的年輕代
