這裏要講的是JVNM的四種垃圾回收算法
1.標記-清除算法
2.複製算法(新生代回收算法)
3.標記-整理算法(老年代回收算法)
4.分代算法
爲什麼要進行垃圾回收?
回收無用的對象,清理無用的內存碎片,分配給新的內存,防止內存溢出或內存泄漏.
怎麼對可回收的對象進行標記?
需要滿足兩個條件:
- 經過可達性分析算法後,不可達的對象
- 覆寫了finalize()方法或者finalize()方法已經被JVM執行過一次
標記-清除算法
算法分爲"標記"和"清除"兩個階段 :
- 首先標記出所有需要回收的對象,
- 在標記完成後統一回收所有被標記的對象
後續的收集算法都是基於這種思路並對其不足加以改進而已。
"標記-清除"算法有哪些不足?
- 效率問題 :
標記和清除這兩個過程的效率都不高
會產生大量不連續的內存碎片
,空間碎片太多可能會導致以後在程序運行中需要分配較大對象時,無法找到足夠連續內存而不得不提前觸發另一次垃圾收集。
複製算法(新生代回收算法)
- "複製"算法是爲了解決"標記-清理"的效率問題。
- 它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。
- 當這塊內存需要進行垃圾回收時,會將此區域還存活着的對象複製到另一塊上面,然後再把已經使用過的內存區域一次清理掉.
- 這樣做的好處是每次都是對整個半區進行內存回收,內存分配時也就不需要考慮內存碎片等複雜情況,只需要移動堆頂指針,按順序分配即可。
- 此算法實現簡單,運行高效
HotSpot實現的複製算法流程如下:
- 當Eden區滿的時候,會觸發第一次Minor gc,把還活着的對象拷貝到Survivor From區;當Eden區再次觸
發Minor gc的時候,會掃描Eden區和From區域,對兩個區域進行垃圾回收,經過這次回收後還存活的對象,
則直接複製到To區域,並將Eden和From區域清空。 - 然後交換from區和to區,誰空誰是to
- 部分對象會在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虛擬機的堆內存不夠:由如下兩種原因
- Java 虛擬機的堆內存設置不夠,可以通過參數 -Xms 、Xmx 來調優
- 代碼中創建了大量大對象,並且長時間不能被垃圾收集器收集(存在被引用)