Java 垃圾回收算法

一、概述

說到垃圾回收,我們必須要知道什么是垃圾?為什么要回收?

  1. 什么是垃圾:垃圾是在程序運(yùn)行中沒有任何指針指向的對象,這個對象就是需要被回收的垃圾。
  2. 為什么要回收:在JVM中如果不及時對垃圾進(jìn)行回收,那么這些垃圾所占的內(nèi)存空間會一直保留到程序結(jié)束,這部分內(nèi)存空間無法被其他對象使用,當(dāng)內(nèi)存占滿的時候就會導(dǎo)致內(nèi)存溢出。

在Java中垃圾回收分為兩個步驟:找到垃圾和回收垃圾。

在找到垃圾的過程中,稱為標(biāo)記階段,其中有兩種算法:引用計數(shù)法,可達(dá)性分析法。
在回收垃圾的過程中,稱為清除階段,對應(yīng)的算法有:標(biāo)記-清除算法,復(fù)制算法,標(biāo)記-整理算法,分代收集算法。

二、引用計數(shù)法

  1. 原理

對每個對象保存一個整型的引用計數(shù)器屬性,每當(dāng)有一個地方引用它時,計數(shù)器+1,當(dāng)引用失效時,計數(shù)器-1,當(dāng)計數(shù)器為0時,說明這個對象不再使用,此時被判定為垃圾。

  1. 優(yōu)點(diǎn):實(shí)現(xiàn)簡單,判斷效率高。
  2. 缺點(diǎn):無法處理循環(huán)引用的情況,這是一個致命的缺點(diǎn),多以Java的垃圾回收器沒有使用這種算法。

循環(huán)引用:
舉一個很簡單的例子:鏈表,鏈表中有一個Next屬性,Next引用的時下一個對象,
A->B->C->D->E->A這種結(jié)構(gòu)。此時將A置空,那么BCDE的引用計數(shù)器還為1,這時就會導(dǎo)致BCDE永遠(yuǎn)無法回收。

三、可達(dá)性分析算法

  1. 原理

以根對象集合(GC Roots)為起始點(diǎn),按照從上到下的方式搜索被根對象集合所鏈接的目標(biāo)對象是否可達(dá)。
搜索的過程中的路徑稱為引用鏈。
如果對象沒有與任何引用鏈相連,則是不可達(dá)的,就意味著這個對象已經(jīng)死亡。

可達(dá)性分析.jpg

可作為GC Roots的有:

  1. 虛擬機(jī)棧中引用的對象。
  2. 本地方法棧內(nèi)JNI引用的對象。
  3. 方法去區(qū)靜態(tài)屬性引用的對象。
  4. 方法區(qū)中常量引用的對象。

在經(jīng)過可達(dá)性分析之后,僅僅進(jìn)行了第一次標(biāo)記,接下來還有第二次標(biāo)記。

  1. 如果對象沒有重寫finalize()方法,則虛擬機(jī)視為沒有必要執(zhí)行,對象被判定不可達(dá)。
  2. 如果對象重寫了finalize()方法,且還未執(zhí)行過,則對象會被插入到F-Queue隊列中,由虛擬機(jī)中一個低優(yōu)先級的Finalizer線程觸發(fā)finalize()方法執(zhí)行。
  3. 在finalize()執(zhí)行的過程中,GC會對F-Queue中的對象進(jìn)行第二次標(biāo)記,如果此對象與引用鏈上的任何一個對象建立了聯(lián)系,那么該對象就會被移出"即將回收"集合,此對象將不會被回收,如果再次出現(xiàn)沒有引用鏈的情況下,finalize()方法不會再調(diào)用,對象直接變成不可達(dá),就是說finalize()方法只會執(zhí)行一次。

四、標(biāo)記-清除算法

  1. 原理

當(dāng)堆中的有效內(nèi)存空間被耗盡時,就會停止整個程序(Stop The World),然后進(jìn)行兩項(xiàng)工作,標(biāo)記和清除。

標(biāo)記:GC從引用根節(jié)點(diǎn)開始遍歷,標(biāo)記所有被引用的對象。
清除:遍歷完成后,如果有對象沒有被標(biāo)記為可達(dá)對象,則將其清除。

這里的清除并不是真正的清除,而是把需要清除的對象地址保存在空閑列表,當(dāng)有新的對象需要插入時,判斷垃圾的位置空間是否足夠,如果夠,則插入。就相當(dāng)于覆蓋。

標(biāo)記-清除.jpg
  1. 優(yōu)點(diǎn):實(shí)現(xiàn)簡單。
  2. 缺點(diǎn):效率不高,清理之后的內(nèi)存空間不連續(xù),產(chǎn)生內(nèi)存碎片。需要維護(hù)一個空閑列表。


五、復(fù)制算法

  1. 原理

將內(nèi)存空間分為兩塊,每次只使用其中一塊,在垃圾回收時將正在使用中的存活對象復(fù)制到未使用的內(nèi)存塊中,然后清除正在使用的內(nèi)存塊的所有對象。最終完成垃圾回收。


復(fù)制算法.jpg
  1. 優(yōu)點(diǎn):沒有標(biāo)記和清除過程,實(shí)現(xiàn)簡單,運(yùn)行高效。復(fù)制后保證了空間連續(xù)性,不會出現(xiàn)碎片問題。
  2. 缺點(diǎn):需要兩倍的空間或者說犧牲一倍的內(nèi)存空間。還要維護(hù)對象的引用關(guān)系,不管是內(nèi)存還是時間開銷都不小。

如果系統(tǒng)中存活對象非常多,復(fù)制算法則需要復(fù)制更多的對象,反而優(yōu)點(diǎn)變成缺點(diǎn),所以復(fù)制算法可以用在數(shù)據(jù)比較小的內(nèi)存中,比如堆中的新生代。

六、標(biāo)記-整理算法

  1. 原理

標(biāo)記整理算法分為三個步驟,標(biāo)記,整理,刪除,它比標(biāo)記-刪除算法多了一步:整理。
標(biāo)記:從根節(jié)點(diǎn)開始標(biāo)記所有被引用的對象。
整理:將所有存活的對象都向一段移動。
刪除:清除邊界外所有的空間。


標(biāo)記-整理.jpg
  1. 優(yōu)點(diǎn):
    1. 解決了標(biāo)記-清除算法的空間不連續(xù)的缺點(diǎn)。
    2. 解決了復(fù)制算法的內(nèi)存減半的代價。
  2. 缺點(diǎn):
    1. 效率低于復(fù)制算法
    2. 移動對象的同時,還需要調(diào)整對象的引用。

七、三種清除算法對比

標(biāo)記-清除 標(biāo)記-整理 復(fù)制
速度 中等 最慢 最快
空間開銷 少(會堆積碎片) 少(不堆積碎片) 對象的2被大小(不堆積碎片)
移動對象


八、分代收集算法

上面總結(jié)了三種回收算法的優(yōu)缺點(diǎn),每種算法都有利有弊,比如復(fù)制算法,雖然它是最快的,但是它會浪費(fèi)一半的空間,所以根據(jù)這些優(yōu)缺點(diǎn),衍生出了分代收集算法。

在JVM堆中,分為新生代和老年代,所以分代收集算法就是針對他們的特點(diǎn)使用最適合的回收算法。

新生代:區(qū)域相對較小,對象生命周期短,存活率低,回收頻繁。自帶Eden和兩個Survivor區(qū),適用復(fù)制算法。

老年代:區(qū)域較大,對象生命周期長,存活率高,回收頻率低。因此適用標(biāo)記-清除或標(biāo)記-整理算法。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • java垃圾回收算法實(shí)現(xiàn)原理,有兩種,一個是引用計數(shù)法,一個是引用可達(dá)法。 引用計數(shù)法,每個對象有一個專門的空間維...
    IT君威少閱讀 977評論 0 2
  • 你不得不懂的GC垃圾回收? 簡介:GC垃圾回收講解 戰(zhàn)略意義 能做出一個需求的同時也要懂得其對應(yīng)的戰(zhàn)略意義 為什么...
    日落_3d9f閱讀 144評論 0 1
  • 垃圾回收算法: ①引用計數(shù)算法:每一塊對象內(nèi)存都保存了一個計數(shù)器,用來記錄當(dāng)前對象被引用的次數(shù),引用計數(shù)算法就是當(dāng)...
    奔跑的Robi閱讀 317評論 0 0
  • 如何確定某個對象是“垃圾”? 引用計數(shù)法給對象添加引用計數(shù)器,每多一個引用的地方就加一,引用失效時就減一,當(dāng)計數(shù)器...
    taoguan閱讀 120評論 0 0
  • 垃圾回收機(jī)制的意義 垃圾回收可以有效的防止內(nèi)存泄露,有效的使用空閑的內(nèi)存;內(nèi)存泄露:指該內(nèi)存空間使用完畢后未回收,...
    醉了俗身醒了初心閱讀 1,575評論 1 0

友情鏈接更多精彩內(nèi)容