1. 程式人生 > >JVM學習之垃圾收集演算法

JVM學習之垃圾收集演算法

以下blog內容來自《深入理解Java虛擬機器_JVM高階特性與最佳實踐》,感謝作者!

昨天下班後地鐵上和以前的同學交談,才知道永遠不嘗試新東西永遠不會有新思路,希望寫完基礎系列之後自己能有所進步,然後分析更多有用的東西。

1垃圾收集演算法分類

       垃圾收集演算法是如何收集物件,也就是如何回收堆及其他被jvm管理的可回收的記憶體的演算法,和書中一樣這裡只按照書本記錄垃圾收集演算法的思路。

垃圾收集演算法:

標記-清除演算法,複製演算法,標記整理演算法,分代收集演算法。

2 標記清除演算法

是最基礎的垃圾收集演算法,之後的演算法都是在此基礎上的改進,標記-清除演算法分成兩個階段,標記和清除;

過程:標記出所有需要回收的物件,標記完成後統一回收所有被標記的物件(怎麼判斷應該被回收請看)。

存在的問題:

(1)效率不高,標記和清除兩個過程效率都不高,

(2)空間問題,標記清除後會產生大量不連續的記憶體碎片(當需要分配大物件時,不連續的記憶體空間無法使用造成浪費)。

借用書中圖:

                                                      

3 複製演算法

      複製演算法為解決標記清除演算法的效率問題,該演算法將可用記憶體劃分成大小相同的兩塊,每次只使用其中一塊。

       具體過程首先用一塊記憶體儲存物件,當這塊記憶體用完時就將還存活著的物件複製到另外一塊上面,然後把已使用過的記憶體空間 一次清理掉。所以每次都是先把存活的物件複製到另外一塊記憶體,然後直接清理掉當前的使用的塊的全部記憶體,效率會更高,

                                                                                                                                           

缺點:

可以看到每次只能使用總記憶體的一半,所以這種演算法比標記清除更浪費記憶體。

雖然浪費記憶體但當今使用的主流JVM的垃圾收集演算法都是採用這種收集演算法回收新生代,但並不是按照1:1的比例來劃分記憶體(絕大多數物件朝生夕死),將記憶體劃分成一塊較大的Eden和兩個較小的Survivor空間,每次使用Eden和其中的一塊Survivor,回收時將Eden和Survivor中還存活的物件一次性複製到另外一個Survivor空間上,之後清理掉Eden和上次使用的Survivor(預設每次存活物件較少,否則可能造成記憶體不夠用,之後需要額外的空間進行分配擔保)。

4 標記-整理演算法

複製演算法在存活物件較多時效率會降低,浪費的記憶體也會更多,所以老年代不適合這種演算法(老年代存活物件較多)。

標記-整理演算法符合老年代的特點,也是首先進行標記,之後不是直接清除而是讓所有存活物件向一端移動,這樣就不會存在記憶體碎片,最後清理掉端邊界以外的記憶體。

                                                                              

5分代收集演算法

分代收集演算法把記憶體劃分成新生代和老年代,新生代物件存活較少,老年代存活物件較多,所以兩個區域採用不同的垃圾收集演算法,新生代利用複製演算法,老年代利用標記-整理或者標記-清除演算法進行物件回收。