JVM垃圾回收收機制

這裏要講的是JVNM的四種垃圾回收算法
1.標記-清除算法
2.複製算法(新生代回收算法)
3.標記-整理算法(老年代回收算法)
4.分代算法


爲什麼要進行垃圾回收?

回收無用的對象,清理無用的內存碎片,分配給新的內存,防止內存溢出或內存泄漏.


怎麼對可回收的對象進行標記?

需要滿足兩個條件:

  • 經過可達性分析算法後,不可達的對象
  • 覆寫了finalize()方法或者finalize()方法已經被JVM執行過一次

標記-清除算法

算法分爲"標記"和"清除"兩個階段 :

  • 首先標記出所有需要回收的對象,
  • 在標記完成後統一回收所有被標記的對象

後續的收集算法都是基於這種思路並對其不足加以改進而已。

"標記-清除"算法有哪些不足?

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

在這裏插入圖片描述


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

  • "複製"算法是爲了解決"標記-清理"的效率問題。
  • 它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊
  • 當這塊內存需要進行垃圾回收時,會將此區域還存活着的對象複製到另一塊上面,然後再把已經使用過的內存區域一次清理掉.
  • 這樣做的好處是每次都是對整個半區進行內存回收,內存分配時也就不需要考慮內存碎片等複雜情況,只需要移動堆頂指針,按順序分配即可。
  • 此算法實現簡單,運行高效

HotSpot實現的複製算法流程如下:

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

在這裏插入圖片描述

  • 新生代中98%的對象都是"朝生夕死"的,所以並不需要按照1 : 1的比例來劃分內存空間,而是將內存(新生代內存)分爲一塊較大的Eden(伊甸園)空間和兩塊較小的Survivor(倖存者)空間,每次使用Eden和其中一塊Survivor(兩個Survivor區域一個稱爲From區,另一個稱爲To區域)。當回收時,將Eden和Survivor中還存活的對象一次性複製到另一塊Survivor空間上,最後清理掉Eden和剛纔用過的Survivor空間。
  • 當Survivor空間不夠用時,需要依賴其他內存(老年代)進行分配擔保。
  • HotSpot默認Eden與Survivor的大小比例是8 : 1,也就是說Eden:Survivor From : Survivor To = 8:1:1。所以每次新生代可用內存空間爲整個新生代容量的90%,而剩下的10%用來存放回收後存活的對象。

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

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

在這裏插入圖片描述


分代收集算法

  • 當前JVM垃圾收集都採用的是"分代收集(Generational Collection)"算法,這個算法並沒有新思想,只是根據對象存活週期的不同將內存劃分爲幾塊。
  • 一般是把Java堆分爲新生代和老年代。
  • 在新生代中,每次垃圾回收都有大批對象死去,只有少量存活,因此我們採用複製算法;
  • 而老年代中對象存活率高、沒有額外空間對它進行分配擔保,就必須採用"標記-清理"或者"標記-整理"算法。

請問了解Minor GC和Full GC麼,這兩種GC有什麼不一樣嗎

  • minor GC發生在新生代,大多數對象都是朝生夕死,因此Minor GC比較頻繁,執行效率也較快
  • Full GC又叫老年代GC或Major GC:發生在老年代的GC, Full GC會出現所謂的STW(stop the world)現象,即所有的進程都掛起等待清理垃圾,Major GC的速度一般會比Minor GC慢10倍以上 ,速度非常慢

如果出現 java.lang.OutOfMemoryError : Java heap space 異常,說明Java虛擬機的堆內存不夠:由如下兩種原因

  1. Java 虛擬機的堆內存設置不夠,可以通過參數 -Xms 、Xmx 來調優
  2. 代碼中創建了大量大對象,並且長時間不能被垃圾收集器收集(存在被引用)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章