1. 程式人生 > >Java垃圾回收算法

Java垃圾回收算法

分代 清理 java 利用 效果 大小 ava 大量 思想

1.標記-清除算法

概念

標記階段:先通過根節點,標記所有從根節點開始的可達對象,因此,未被標記的對象就是未被引用的垃圾對象;

清除階段:清除所有未被標記的對象。

缺點:

標記和清除的過程效率不高(標記和清除都需要從頭便利到尾)

標記清除後會產生大量不連續的碎片。

2.復制算法

概念:

將原有的內存空間氛圍兩塊,每次只是用其中一塊,在垃圾回收時,將正在使用放內存中的存活的對象復制到位使用的內存塊中,飯後清除正在使用放內存塊中放所有對象。

優點:

這樣使得每次都是對整個搬去與進行回收,內存分配時也就不用考慮內存碎片等情況,只要移動堆頂指針按順序分配內存即可,實現簡單,運行效率高。

缺點:空間的浪費

從以上描述不難看出,復制算法要想使用,最起碼對象的存活率要非常低才行。

現在的商業虛擬機都采用這種手機算法來回收新生代,新生代的對象98%都是朝生夕死的,所以並不需要按照1:1的比例來劃分內存空間,而是將內存分為一塊比較大的Eden空間和兩塊比較小的Survivor空間,每次使用Eden和其中一塊Survivor。當回收時,將Eden和Survivor中還存活的對象一次性的復制到另外一個Survivor空間上,最後清理掉Eden和剛才用過的Survivor空間。HotSpot虛擬機默認Eden和Survivor的大小比例是8:1,也就是所,每次新生代中可使用內存空間為整個新生代容量的90%,只有10&的空間會被浪費。

當然,98%的對象可回收只是一般場景下的數據,我們沒有辦法保證每次回收都只有不多於10%的對象存活,當Survivor空間不夠用時,需要依賴於老年代進行分配擔保,所以大對象直接進入老年代,整個過程如下圖所示。

技術分享

標記-整理算法(老年代的GC)

復制算法在對象存活率高的時候要進行較多的復制操作,效率將會減低,所以在老年代中一般不能直接使用這種算法。

概念:

標記階段:

先通過根節點,標記所有從根節點開始的可達對象,因此,未被標記的對象就是未被引用的垃圾對象。

整理階段:將所有的存活對象壓縮到內存的一端;之後,清理邊界外所有的空間。

優點:

不會產生內存碎片。

缺點:

在標記的基礎之上還需要進行對象的移動,成本相對較高,效率也不高。

他們的區別(>表示前者要優於後者,=表示兩者效果一樣)

(1)效率:復制算法》標記-整理算法》標記清除算法(此處的效率只是簡單地對比時間復雜度,實際情況不一定如此)

(2)內存整齊度:復制算法=標記-整理算法》標記清除算法

(3)內存利用率:標記-整理算法=標記-清除算法》復制算法

註意1標記整理算法不僅可以彌補標記-清除算法當中內存區域分散的缺點,也消除了復制算法當中,內存減半的高額代價。

註意2:可以看到標記-清除算法是比較落後的算法了,但是後兩種算法卻是在此基礎上建立是。

註意3:時間與空間不可兼得。

4.分代收集算法

當前商業虛擬機的GC都是采用的分代收集算法,這並不是什麽新的思想,只是根據對象放存活周期的不用內存劃分為幾塊,一般是吧Java堆分為新生代和老年代:短命對象歸為新生代,長命對象歸為老年代。

存活率低:少量對象存活,適合膚質算法:在新生代中,每次GC時都發現有大批對象死去,只有少量存活(新生代中98%的對象都是朝生夕死的),那就選用復制算法,只需要付出少量存活對象的復制成本就可以完成GC。

存活率高:大量對象存活,適合用標記-清理、標記-整理;在老年代中,因為對象存活率高,沒有額外的空間對他進行分配擔保,就必須使用“標記-清理”或者“標記-整理”算法進行GC。

註意:老年代的對象中,有一小部分因為在新生代會收拾,老年代做擔保,進來的對象;絕大部分對象是因為很多次GC都沒有被回收掉而進入老年代。

Java垃圾回收算法