1.標(biāo)記清除
標(biāo)記-清除算法將垃圾回收分為兩個階段:標(biāo)記階段和清除階段。
在標(biāo)記階段首先通過根節(jié)點(GC Roots)表鳍,標(biāo)記所有從根節(jié)點開始的對象,未被標(biāo)記的對象就是未被引用的垃圾對象。然后仑嗅,在清除階段,清除所有未被標(biāo)記的對象张症。
適用場合:
?存活對象較多的情況下比較高效
?適用于年老代(即舊生代)
缺點:
?容易產(chǎn)生內(nèi)存碎片仓技,再來一個比較大的對象時(典型情況:該對象的大小大于空閑表中的每一塊兒大小但是小于其中兩塊兒的和),會提前觸發(fā)垃圾回收
?掃描了整個空間兩次(第一次:標(biāo)記存活對象俗他;第二次:清除沒有標(biāo)記的對象)
2.復(fù)制算法
從根集合節(jié)點進(jìn)行掃描脖捻,標(biāo)記出所有的存活對象,并將這些存活的對象復(fù)制到一塊兒新的內(nèi)存(圖中下邊的那一塊兒內(nèi)存)上去兆衅,之后將原來的那一塊兒內(nèi)存(圖中上邊的那一塊兒內(nèi)存)全部回收掉
現(xiàn)在的商業(yè)虛擬機都采用這種收集算法來回收新生代地沮。
適用場合:
?存活對象較少的情況下比較高效
?掃描了整個空間一次(標(biāo)記存活對象并復(fù)制移動)
適用于年輕代(即新生代):基本上98%的對象是”朝生夕死”的,存活下來的會很少
缺點:
?需要一塊兒空的內(nèi)存空間
?需要復(fù)制移動對象
3.標(biāo)記整理
復(fù)制算法的高效性是建立在存活對象少羡亩、垃圾對象多的前提下的摩疑。
這種情況在新生代經(jīng)常發(fā)生,但是在老年代更常見的情況是大部分對象都是存活對象畏铆。如果依然使用復(fù)制算法雷袋,由于存活的對象較多,復(fù)制的成本也將很高辞居。
標(biāo)記-壓縮算法是一種老年代的回收算法楷怒,它在標(biāo)記-清除算法的基礎(chǔ)上做了一些優(yōu)化。
首先也需要從根節(jié)點開始對所有可達(dá)對象做一次標(biāo)記瓦灶,但之后鸠删,它并不簡單地清理未標(biāo)記的對象,而是將所有的存活對象壓縮到內(nèi)存的一端倚搬。之后冶共,清理邊界外所有的空間乾蛤。這種方法既避免了碎片的產(chǎn)生每界,又不需要兩塊相同的內(nèi)存空間,因此眨层,其性價比比較高庙楚。
4.分代收集算法
分代收集算法就是目前虛擬機使用的回收算法趴樱,它解決了標(biāo)記整理不適用于老年代的問題,將內(nèi)存分為各個年代叁征。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation),在堆區(qū)之外還有一個代就是永久代(Permanet Generation)捺疼。
在不同年代使用不同的算法,從而使用最合適的算法啤呼,新生代存活率低,可以使用復(fù)制算法官扣。而老年代對象存活率搞翅敌,沒有額外空間對它進(jìn)行分配擔(dān)保惕蹄,所以只能使用標(biāo)記清除或者標(biāo)記整理算法。
垃圾回收機制
年輕代分為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)重)竹捉。
垃圾回收有兩種類型:Minor GC 和 Full GC芜辕。
1.Minor GC
對新生代進(jì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. 每一種算法都會有很多不同的垃圾回收器去實現(xiàn),在實際使用中征候,根據(jù)自己的業(yè)務(wù)特點做出選擇就好祟敛。