垃圾回收算法

1.標(biāo)記清除

標(biāo)記-清除算法將垃圾回收分為兩個階段:標(biāo)記階段和清除階段。

在標(biāo)記階段首先通過根節(jié)點(diǎn)(GC Roots),標(biāo)記所有從根節(jié)點(diǎn)開始的對象,未被標(biāo)記的對象就是未被引用的垃圾對象。然后,在清除階段,清除所有未被標(biāo)記的對象。

適用場合

?存活對象較多的情況下比較高效

?適用于年老代(即舊生代)

缺點(diǎn)

?容易產(chǎn)生內(nèi)存碎片,再來一個比較大的對象時(典型情況:該對象的大小大于空閑表中的每一塊兒大小但是小于其中兩塊兒的和),會提前觸發(fā)垃圾回收

?掃描了整個空間兩次(第一次:標(biāo)記存活對象;第二次:清除沒有標(biāo)記的對象)

2.復(fù)制算法

從根集合節(jié)點(diǎn)進(jìn)行掃描,標(biāo)記出所有的存活對象,并將這些存活的對象復(fù)制到一塊兒新的內(nèi)存(圖中下邊的那一塊兒內(nèi)存)上去,之后將原來的那一塊兒內(nèi)存(圖中上邊的那一塊兒內(nèi)存)全部回收掉

現(xiàn)在的商業(yè)虛擬機(jī)都采用這種收集算法來回收新生代。

適用場合:

?存活對象較少的情況下比較高效

?掃描了整個空間一次(標(biāo)記存活對象并復(fù)制移動)

用于年輕代(即新生代):基本上98%的對象是”朝生夕死”的,存活下來的會很少

缺點(diǎn):

?需要一塊兒空的內(nèi)存空間

?需要復(fù)制移動對象

3.標(biāo)記整理

復(fù)制算法的高效性是建立在存活對象少、垃圾對象多的前提下的。

這種情況在新生代經(jīng)常發(fā)生,但是在老年代更常見的情況是大部分對象都是存活對象。如果依然使用復(fù)制算法,由于存活的對象較多,復(fù)制的成本也將很高。

標(biāo)記-壓縮算法是一種老年代的回收算法,它在標(biāo)記-清除算法的基礎(chǔ)上做了一些優(yōu)化。

首先也需要從根節(jié)點(diǎn)開始對所有可達(dá)對象做一次標(biāo)記,但之后,它并不簡單地清理未標(biāo)記的對象,而是將所有的存活對象壓縮到內(nèi)存的一端。之后,清理邊界外所有的空間。這種方法既避免了碎片的產(chǎn)生,又不需要兩塊相同的內(nèi)存空間,因此,其性價比比較高。

4.分代收集算法

分代收集算法就是目前虛擬機(jī)使用的回收算法,它解決了標(biāo)記整理不適用于老年代的問題,將內(nèi)存分為各個年代。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation),在堆區(qū)之外還有一個代就是永久代(Permanet Generation)。

在不同年代使用不同的算法,從而使用最合適的算法,新生代存活率低,可以使用復(fù)制算法。而老年代對象存活率搞,沒有額外空間對它進(jìn)行分配擔(dān)保,所以只能使用標(biāo)記清除或者標(biāo)記整理算法。

垃圾回收機(jī)制

年輕代分為Eden區(qū)和survivor區(qū)(兩塊兒:from和to),且Eden:from:to==8:1:1。

jvm內(nèi)存結(jié)構(gòu)

1)新產(chǎn)生的對象優(yōu)先分配在Eden區(qū)(除非配置了-XX:PretenureSizeThreshold,大于該值的對象會直接進(jìn)入年老代);

2)當(dāng)Eden區(qū)滿了或放不下了,這時候其中存活的對象會復(fù)制到from區(qū)。

這里,需要注意的是,如果存活下來的對象from區(qū)都放不下,則這些存活下來的對象全部進(jìn)入年老代。之后Eden區(qū)的內(nèi)存全部回收掉。

3)之后產(chǎn)生的對象繼續(xù)分配在Eden區(qū),當(dāng)Eden區(qū)又滿了或放不下了,這時候?qū)袳den區(qū)和from區(qū)存活下來的對象復(fù)制到to區(qū)(同理,如果存活下來的對象to區(qū)都放不下,則這些存活下來的對象全部進(jìn)入年老代),之后回收掉Eden區(qū)和from區(qū)的所有內(nèi)存。

4)如上這樣,會有很多對象會被復(fù)制很多次(每復(fù)制一次,對象的年齡就+1),默認(rèn)情況下,當(dāng)對象被復(fù)制了15次(這個次數(shù)可以通過:-XX:MaxTenuringThreshold來配置),就會進(jìn)入年老代了。

5)當(dāng)年老代滿了或者存放不下將要進(jìn)入年老代的存活對象的時候,就會發(fā)生一次Full GC(這個是我們最需要減少的,因?yàn)楹臅r很嚴(yán)重)。

垃圾回收有兩種類型:Minor GC 和 Full GC。

1.Minor GC

對新生代進(jìn)行回收,不會影響到年老代。因?yàn)樾律?Java 對象大多死亡頻繁,所以 Minor GC 非常頻繁,一般在這里使用速度快、效率高的算法,使垃圾回收能盡快完成。

2.Full GC

也叫

Major GC,對整個堆進(jìn)行回收,包括新生代和老年代。由于Full GC需要對整個堆進(jìn)行回收,所以比Minor

GC要慢,因此應(yīng)該盡可能減少Full GC的次數(shù),導(dǎo)致Full

GC的原因包括:老年代被寫滿、永久代(Perm)被寫滿和System.gc()被顯式調(diào)用等。

垃圾回收算法總結(jié)

1.年輕代:復(fù)制算法

1) 所有新生成的對象首先都是放在年輕代的。年輕代的目標(biāo)就是盡可能快速的收集掉那些生命周期短的對象。

2)

新生代內(nèi)存按照8:1:1的比例分為一個eden區(qū)和兩個survivor(survivor0,survivor1)區(qū)。一個Eden區(qū),兩個

Survivor區(qū)(一般而言)。大部分對象在Eden區(qū)中生成。回收時先將eden區(qū)存活對象復(fù)制到一個survivor0區(qū),然后清空eden區(qū),當(dāng)這個survivor0區(qū)也存放滿了時,則將eden區(qū)和survivor0區(qū)存活對象復(fù)制到另一個survivor1區(qū),然后清空eden和這個survivor0區(qū),此時survivor0區(qū)是空的,然后將survivor0區(qū)和survivor1區(qū)交換,即保持survivor1區(qū)為空,

如此往復(fù)。

3) 當(dāng)survivor1區(qū)不足以存放 eden和survivor0的存活對象時,就將存活對象直接存放到老年代。若是老年代也滿了就會觸發(fā)一次Full GC(Major GC),也就是新生代、老年代都進(jìn)行回收。

4) 新生代發(fā)生的GC也叫做Minor GC,MinorGC發(fā)生頻率比較高(不一定等Eden區(qū)滿了才觸發(fā))。

2.年老代:標(biāo)記-清除或標(biāo)記-整理

1) 在年輕代中經(jīng)歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認(rèn)為年老代中存放的都是一些生命周期較長的對象。

2) 內(nèi)存比新生代也大很多(大概比例是1:2),當(dāng)老年代內(nèi)存滿時觸發(fā)Major GC即Full GC,F(xiàn)ull GC發(fā)生頻率比較低,老年代對象存活時間比較長,存活率標(biāo)記高。

以上這種年輕代與年老代分別采用不同回收算法的方式稱為”分代收集算法”,這也是當(dāng)下企業(yè)使用的一種方式

3. 每一種算法都會有很多不同的垃圾回收器去實(shí)現(xiàn),在實(shí)際使用中,根據(jù)自己的業(yè)務(wù)特點(diǎn)做出選擇就好。

?著作權(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)容

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