JVM系列二(垃圾收集算法).
- 2019 年 12 月 17 日
- 筆記
一、標記-清除算法(Mark-Sweep)
這種算法分為「標記」和「清除」兩個階段:首先標記出所有需要回收的對象,在標記完成後統一回收所有被標記的對象。
Mark-Sweep 算法是最基礎的收集算法,幾乎所有的收集算法都是基於這種思路並對其不足進行改進而得到。它的不足之處主要有兩個:
- 效率問題。標記和清除兩個過程的效率都不高;
- 空間問題。標記清除之後會產生大量的內存碎片,空間碎片太多可能會導致在需要分配較大對象時,無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。
二、複製算法(Copying)
這種算法將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊內存用完了,就將標記存活的對象複製到另外一塊上面,然後再把已使用的半區空間一次性清理掉。
Copying 算法每次都只對半區進行回收,很好的解決了內存碎片的問題,而且實現簡單,運行高效。
該算法的不足之處在於:
- 將內存縮小為原來的一半,代價高昂,並且需要額外空間做分配擔保。
- 在對象存活率較高的時就要進行較多的複製操作,效率降低。
現在的商用虛擬機都採用這種收集算法來回收新生代。
三、標記-整理算法(Mark-Compact)
這種算法分為「標記」和「整理」兩個階段:首先標記出所有需要回收的對象,然後讓所有存活的對象都向一端移動,接着直接清理掉端邊界以外的內存。
Mark-Compact 算法在解決內存碎片的同時,避免 Copying 算法的空間浪費和效率問題。
四、分代收集算法(Generational Collection)
這種算法根據對象存活周期的不同將內存劃分為幾塊,一般把 Java 堆分為新生代和老生代。
在新生代,每次垃圾收集時都發現有大批對象死去,只有少量存活,那就選用 Copying 算法,只要付出少量存活對象的複製成本就可以完成收集。
在老生代,對象存活率高,沒有額外空間對它進行擔保,就必須使用 Mark-Sweep 或者 Mark-Compact 算法。