《深入理解Java虛擬機器》(二)--垃圾收集器與記憶體分配策略(2)

weixin_34107955發表於2018-05-28

垃圾收集演算法:

1/1 標記-清除演算法(Mark-Sweep):

最基礎的垃圾回收演算法,它分為兩個階段,標記和清除:首先它會標記出所有需要回收的物件,在標記完成之後統一回收所有被標記物件,它的標記過程之前已經提到了。

缺點:

1、效率低:它的標記和清除兩個過程效率都不高。
2、空間問題:因為標記和清除之後會產生大量的不連續的片段,空間碎片太多可能會導致以後需要分配大物件的過程中,由於無法找到足夠的連續記憶體而不得不提前觸發一次垃圾收集。
具體過程如下:


12350543-3e66997808c40c25.png
標記-清除演算法的具體過程

1/2 複製演算法(Copying):

複製演算法是將可用的記憶體按照容量大小分為相等的兩塊,每次只使用其中的一塊,當這一塊的記憶體用完了,就將上面還存活的物件複製到另一塊沒用過的記憶體中,然後清理之前使用過的記憶體。

優點:

這樣的演算法使得每次都對整個半區進行記憶體回收,記憶體分配時也不用考慮記憶體碎片等複雜情況,只要移動堆頂指標,按順序分配記憶體即可,實現簡單,執行高效。

缺點:

這種演算法的代價是將能夠使用的記憶體縮小為原來的一半,浪費的資源太多了。
具體的過程如下:


12350543-e7f74130af5c75c4.png
複製演算法的具體執行過程
新生代和老年代:

新生代指的是頻繁出生和死亡的物件區域,相反老年代的物件都比較穩定。

改進:

其實新生代中的大部分物件是“朝生夕死”,生命很短,也就是說存活的物件很少,所以並不需要按照1:1的比例去分配記憶體空間,在HotSpot虛擬機器中,是將一塊記憶體分為一塊較大的記憶體空間Eden和兩塊較小的空間Survivor,他們的預設比例是8:1:1,每次使用的是Eden和其中的一塊Survivor。當回收時,將Eden和那塊Survivor中還存活的物件(因為是新生代,所以很少)全部複製到另一塊Survivor中,最後清理掉剛才所使用的Eden和Survivor,這樣每次只有10%會被“浪費掉”,解決了浪費資源太多的問題。雖然新生代中的存活物件很少,但有的時候還是會超過那10%的記憶體空間,當那塊Survivor空間不夠用的時候,這些物件將直接通過分配擔保機制進入老年代。

1/3 標記-整理演算法(Mark-Compact):

如果在物件存活情況較多的時候(老年代中),顯然,複製收集演算法的效率會很低,為了應對這種情況,老年代中一般選用標記-整理演算法。
標記整理演算法的標記過程與標記清除演算法一樣,但是後續的步驟是將存活的物件向著內部的邊界(比如上邊)移動,也就是說移動完之後,存活的物件都緊挨著,然後直接清除掉存活物件以外的物件。
具體過程如下:


12350543-90195b12fb53e98f.png
標記-整理演算法的具體過程

1/4 分代收集演算法:

分代收集演算法並不是一種特定的演算法,它是根據物件存活週期的不同將記憶體劃分為幾塊,一般是將Java堆分成新生代和老年代,這樣根據各個年代的特點選擇最適合的垃圾收集演算法,新生代中物件頻繁的建立和死去,就使用複製演算法,老年代的物件比較穩定,就使用標記-清除或者標記-整理演算法。

相關文章