jvm 垃圾收集算法

通過上篇如何判斷對象是否死亡,那麼jvm要對死亡的對象進行垃圾回收,垃圾回收的算法主要有如下幾種:java

1、標記-清楚算法

該算法分爲「標記」和「清除」階段:首先標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象。它是最基礎的收集算法,後續的算法都是對其不足進行改進獲得。這種垃圾收集算法會帶來兩個明顯的問題:算法

  • 一個是效率問題,標記和清除兩個過程的效率都不高
  • 一個是空間問題,標記清除以後會產生大量不連續的內存碎片,空間碎片太多可能會致使之後在程序運行過程當中須要分配較大對象時,沒法找到足夠的連續內存而不得不提早觸發另外一次垃圾收集動做

黑色表明要回收的對象,灰色表明不用回收的對象,白色表明空閒的內存。jvm

2、複製算法

爲了解決效率問題,「複製」收集算法出現了。它能夠將內存分爲大小相同的兩塊,每次使用其中的一塊。當這一塊的內存使用完後,就將還存活的對象複製到另外一塊去,而後再把使用的空間一次清理掉。這樣就使每次的內存回收都是對內存區間的一半進行回收。spa

這樣使得每次都是對整個半區進行內存回收,內存分配時也就不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配內存便可,實現簡單,運行高效。指針

如今的商業虛擬機都採用這種收集算法來回收新生代,研究代表,新生代中的對象 98%是「朝生夕死」的,因此並不須要按照 1:1 的比例來劃份內存空間,而是將內存分爲一塊較大的 Eden 空間和兩塊較小的 Survivor 空間,每次使用 Eden 和其中一塊 Survivor。 Survivor from 和Survivor to ,內存比例 8:1:1對象

當回收時,將 Eden 和 Survivor 中還存活着的對象一次性地複製到另一塊 Survivor 空間上,最後清理掉 Eden 和剛纔用過的 Survivor 空間。HotSpot 虛擬機默認 Eden 和 Survivor 的大小比例是 8:1, 也就是每次新生代中可用內存空間爲整個新生代容量的 90% (80%+10%),只有 10% 的內存會被「浪費」。固然,98%的對象可回收只是通常場景下的數據,咱們沒有辦法保證每次回收都只有很少於 10%的對象存活,當 Survivor 空間不夠用時,須要依賴其餘內存(這裏指老年代)進行分配擔保(Handle Promotion)。blog

3、標記-整理算法

根據老年代的特色提出的一種標記算法,標記過程仍然與「標記-清除」算法同樣,但後續步驟不是直接對可回收對象回收,而是讓全部存活的對象向一端移動,而後直接清理掉端邊界之外的內存。內存

標記整理算法解決了什麼問題虛擬機

複製收集算法在對象存活率較高時就要進行較多的複製操做,效率將會變低。更關鍵的是,若是不想浪費 50%的空間,就須要有額外的空間進行分配擔保,以應對被使用的內存中全部對象都 100%存活的極端狀況,因此在老年代通常不能直接選用這種算法io

4、分代收集算法

當前虛擬機的垃圾收集都採用分代收集算法,這種算法沒有什麼新的思想,只是根據對象存活週期的不一樣將內存分爲幾塊。通常將 java 堆分爲新生代和老年代,這樣咱們就能夠根據各個年代的特色選擇合適的垃圾收集算法。

好比在新生代中,每次收集都會有大量對象死去,因此能夠選擇複製算法,只須要付出少許對象的複製成本就能夠完成每次垃圾收集。而老年代的對象存活概率是比較高的,並且沒有額外的空間對它進行分配擔保,因此咱們必須選擇「標記-清除」或「標記-整理」算法進行垃圾收集。

相關文章
相關標籤/搜索