標記-清除算法(Mark-Sweep)
算法分為:“標記”和“清除”兩個階段。
主要不足:
1)效率問題:標記和清除兩個過程的效率都不高
2)空間問題:標記清除之後會產生大量不連續的內存碎片,空間碎片太多可能會導致以後在程序運行過程中需要分配較大對象時,無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。
標記--清除算法示意圖:
復制算法(Copying)
它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中一塊。當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然後再把已使用過的內存空間一次清理掉。
這樣使得每次都是對整個半區進行內存回收,內存分配時也就不用考慮內存碎片等復雜情況,只要移動堆頂指針,按順序分配內存即可。
代價:將內存縮小為了原來的一半,未免太高了一點。
商業虛擬機都采用這種收集算法回收新生代。
HotSpot虛擬機默認Eden:Survivor = 8:1。
當Survivor空間不夠用時,需要依賴其它內存(這裡指老年代)進行分配擔保(Handle Promotion)。
復制算法示意圖:
標記-整理算法(Mark-Compact)
根據老年代的特點,有人提出了另外一種”標記-整理“(Mark-Compact)算法,標記過程仍然與”標記-清理“算法一樣,但後續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然後直接清理掉端邊界以外的內存。
分代收集算法(Generational Collection)
當前商業虛擬機的垃圾收集都采用”分代收集“算法,根據對象存活周期的不同將內存劃分為幾塊。
一般是把Java堆分為新生代和老生代。在新生代中,每次垃圾收集是都發現有大批對象死去,只有少量存活,那就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行分配擔保,就必須使用”標記-清理“或者”標記-整理“算法來進行回收。