深入理解Java虛擬機(三)垃圾回收算法


  在我們知道了如何判斷對象已“死”? 之後我們就要去回收內存空間,垃圾回收算法主要有一下幾種:

  1. 標記-清除算法
  2. 複製算法
  3. 標記整理算法
  4. 分代收集算法

1. 標記-清除算法

  “標記-清除”算法是最基礎的收集算法。算法分爲 “標記”“清除” 兩個階段:

  1. 標記: 遍歷堆,標記出所有需要回收的對象(此處採用的是可達性分析算法進行標記)
  2. 清除: 標記結束後,再次遍歷堆,統一回收所以被標記的對象。

在這裏插入圖片描述

通過上述過程我們可以感覺到“標記-清除”法的不足:

  1. 效率問題:標記、清除分爲兩次進行且每次都要遍歷全部空間,可以發現標記和清除這兩個過程的效率都不高。
  2. 空間問題:標記清除後我們會產生大量不連續的內存碎片,空間碎片太多可能會導致後面在程序運行中需要分配較大對象時,無法找到足夠連續內存而不能不提前觸發另一次垃圾回收。

可能第二個不足,通過上面的圖解不是很清楚,我們再來畫一個圖:

通過上面圖,我們可以發現使用的空間都沒有集中起來,導致該算法進行中出現的效率和空間問題。

2. 複製算法(新生代回收算法)

“複製”算法是爲了解決“標記-清除”的效率問題。
算法概述:
  複製算法將可用內存按容量劃分爲大小相等的兩塊,每次只是用其中的一塊。當這塊內存需要垃圾回收時,會將此區域還存活着的對象複製到另一塊上面,然後再把已經使用過的內存區域一次清理掉。
在這裏插入圖片描述
優點: 該算法的好處時,每次都是對整個搬去進行內存回收,內存分配時也就不需要考慮內存碎片等複雜情況,只需要移動堆頂指針,按順序分配即可。該算法實現相對“標記-清除”簡單,運行高效。
現在商用的虛擬機(包括HotSpot都是採用這種收集算法來回收新生代)。

在新生代使用複製收集算法的原因: 新生代中98%的對象都是“朝生夕死”的,所以複製的對象很少,效率較高。
  新生代使用了複製收集算法,那麼它的空間是怎麼劃分的,由於上面有說“新生代中98%的對象都是朝生夕死的”,所以不需要按照1:1的比例來劃分內存空間,而是將內存(新生代內存)分爲一塊較大的Eden空間和兩塊較小的Survivor空間(兩個Survivor區域一個稱爲Fro’m區,另一個稱爲To區域),每次使用Eden和其中一塊Survivor空間。當回收時將Eden和Survivor中還存活的對象一次性複製到另一塊Survivor空間上,最後清理掉Eden和剛纔用過的Survivor空間。
  當Survivor空間不夠用時,需要依賴其他內存空間(老年代)進行分配擔保。
內存空間分配如下圖所示:
在這裏插入圖片描述
注意: HotSpot默認的Eden和Survivor的大小比例時8:1,也就是說Eden:Survivor From:Survivor To = 8:1:1。所以每次新生代可用內存空間爲整個新生代容量的90%,而剩下的10%用來存放回收後的存活對象。
  瞭解了複製算法的思想,也知道了HotSpot的內存分配,下面我們來看一下HotSpot實現複製算法的流程:

  1. 當Eden區滿的時候,會觸發第一次Minor gc,把或者的對象拷貝到Survivor From區;當Eden區再次觸發Minor gc的時候,這次會掃描Eden區和From區,對這兩個區域進行垃圾回收,經過這次回收還存活的的對象,則直接複製到To區域,並將Eden和From區域清空。
  2. 當後續Eden又發生Minor gc的時候,會對Eden和To區域進行垃圾回收,存活的對象複製到From區域,並將Eden和To區域清空。
  3. 部分對象會在From和To區域中來回複製,如此交換15次(由JVM參數MaxTenuringThreshold決定,這個參數默認是15),最終如果對象還是存活,就存入老年代。

在這裏插入圖片描述

3. 標記-整理算法(老年代回收算法)

複製收集算法再對象存活率較高時會進行比較多的複製操作,效率會變低。因此老年代一般不能使用複製算法。針對老年代的特點,提出了一種“標記-整理”算法。標記過程仍與“標記-清除”算法過程一致,但後續步驟不是直接堆可回收對象進行清理,而是讓所有存活對象都向一端移動,然後直接清理掉端邊緣以外的內存。
在這裏插入圖片描述

4. 分代收集算法

  當前JVM垃圾收集都採用的是“分代收集”算法,這個算法並沒有新思想,只是根據對象存活週期的不同將內存劃分爲幾塊。
  一般是把Java堆分爲新生代和老年代。

  • 新生代中,每次垃圾回收都有大批量對象死去,只有少量存活因此我們採用複製算法
  • 老年代中,***對象的存活效率高、沒有額外的空間對它進行分配擔保,***就必須採用“標記-清理”或“標記-整理”算法。

5. Minor gc 和 Full gc

在上面我們不停的在說Minor gc,那麼他到底是什麼?還有一種Full gc,這兩種GC有什麼不一樣嗎?

  • Minor gc(新生代gc):指發生在新生代的垃圾收集因爲Java對象大多都具備朝生夕滅的特點,因此Minor gc(採用複製算法)非常頻繁,一般回收速度也比較快
  • Full gc(老年代gc 或者 Major gc):指發生在老年代的垃圾收集出現了Major gc,經常伴隨至少一次的Minor gc並非絕對,在Paraellel Scavenge收集器中就有直接進行Full gc的策略選擇過程)。Major gc的速度會比一般的Minor gc慢10倍以上。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章