在《Java虛擬機垃圾回收(一) 基礎》中瞭解到如何判斷對象是存活還是已經死亡? 介紹了垃圾回收基礎算法:引用計數算法、可達性分析算法,以及HotSpot虛擬機中實現對象可達性分析的一些問題。
下面先來了解Java虛擬機垃圾回收的幾種常見算法:標記-清除算法、複製算法、標記-整理算法、分代收集算法、火車算法,介紹它們的算法思路,有什麼優點和缺點,以及主要應用場景。
1、標記-清除算法
標記-清除(Mark-Sweep)算法是一種基礎的收集算法。
1、算法思路
"標記-清除"算法,分爲兩個階段:
(A)、標記
首先標記出所有需要回收的對象;
標記過程如《Java虛擬機垃圾回收(一) 基礎》"2-4、判斷對象生存還是死亡"中所述--分爲兩個標記過程(詳細請參考前文):
(1)、第一次標記
在可達性分析後發現對象到GC Roots沒有任何引用鏈相連時,被第一次標記;
並且進行一次篩選:此對象是否必要執行finalize()方法;
對有必要執行finalize()方法的對象,被放入F-Queue隊列中;
(2)、第二次標記
GC將對F-Queue隊列中的對象進行第二次小規模標記;
在其finalize()方法中重新與引用鏈上任何一個對象建立關聯,第二次標記時會將其移出"即將回收"的集合;
對第一次被標記,且第二次還被標記(如果需要,但沒有移出"即將回收"的集合),就可以認爲對象已死,可以進行回收。
(B)、清除
兩次標記後,還在"即將回收"集合的對象將被統一回收;
執行過程如下圖:
2、優點
基於最基礎的可達性分析算法,它是最基礎的收集算法;
而後續的收集算法都是基於這種思路並對其不足進行改進得到的;
3、缺點
主要有兩個缺點:
(A)、效率問題
標記和清除兩個過程的效率都不高;
(B)、空間問題
標記清除後會產生大量不連續的內存碎片;
這會導致分配大內存對象時,無法找到足夠的連續內存;
從而需要提前觸發另一次垃圾收集動作;
4、應用場景
針對老年代的CMS收集器;
2、複製算法算法
"複製"(Copying)收集算法,爲了解決標記-清除算法的效率問題;
1、算法思路
(A)、把內存劃分爲大小相等的兩塊,每次只使用其中一塊;
(B)、當一塊內存用完了,就將還存活的對象複製到另一塊上(而後使用這一塊);
(C)、再把已使用過的那塊內存空間一次清理掉,而後重複步驟2;
執行過程如下圖:
2、優點
這使得每次都是隻對整個半區進行內存回收;
內存分配時也不用考慮內存碎片等問題(可使用"指針碰撞"的方式分配內存);
實現簡單,運行高效;
(關於"指針碰撞"請參考《Java對象在HotSpot虛擬機中的創建過程》)
3、缺點
(A)、空間浪費
可用內存縮減爲原來的一半,太過浪費(解決:可以改良,不按1:1比例劃分);
(B)、效率隨對象存活率升高而變低
當對象存活率較高時,需要進行較多複製操作,效率將會變低(解決:後面的標記-整理算法);
4、應用場景
現在商業JVM都採用這種算法(通過改良缺點1)來回收新生代;
如Serial收集器、ParNew收集器、Parallel Scavenge收集器、、G1(從局部看);
5、HotSpot虛擬機的改良算法
(A)、弱代理論
分代垃圾收集基於弱代理論(weak generational hypothesis),具體描述如下:
(1)、大多數分配了內存的對象並不會存活太長時間,在處於年輕代時就會死掉;
(2)、很少有對象會從老年代變成年輕代;
其中IBM研究表明:新生代中98%的對象都是"朝生夕死";
所以並不需要按1:1比例來劃分內存(解決了缺點1);
(B)、HotSpot虛擬機新生代內存佈局及算法
(1)、將新生代內存分爲一塊較大的Eden空間和兩塊較小的Survivor空間;
(2)、每次使用Eden和其中一塊Survivor;
(3)、當回收時,將Eden和使用中的Survivor中還存活的對象一次性複製到另外一塊Survivor;
(4)、而後清理掉Eden和使用過的Survivor空間;
(5)、後面就使用Eden和複製到的那一塊Survivor空間,重複步驟3;
默認Eden:Survivor=8:1,即每次可以使用90%的空間,只有一塊Survivor的空間被浪費;
(C)、分配擔保
如果另一塊Survivor空間沒有足夠空間存放上一次新生代收集下來的存活對象時,這些對象將直接通過分配擔保機制(Handle Promotion)進入老年代;
分配擔保在以後講解垃圾收集器執行規則時再詳解;
更多請參考:http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/generations.html#sthref16
3、標記-整理算法
"標記-整理"(Mark-Compact)算法是根據老年代的特點提出的。
1、算法思路
(1)、標記
標記過程與"標記-清除"算法一樣;
(2)、整理
但後續不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動;
然後直接清理掉端邊界以外的內存;
執行過程如下圖:
2、優點
(A)、不會像複製算法,效率隨對象存活率升高而變低
老年代特點:
對象存活率高,沒有額外的空間可以分配擔保;
所以老年代一般不能直接選用複製算法算法;
而選用標記-整理算法;
(B)、不會像標記-清除算法,產生內存碎片
因爲清除前,進行了整理,存活對象都集中到空間一側;
3、缺點
主要是效率問題:除像標記-清除算法的標記過程外,還多了需要整理的過程,效率更低;
4、應用場景
很多垃圾收集器採用這種算法來回收老年代;
如Serial Old收集器、G1(從整體看);
4、分代收集算法
"分代收集"(Generational Collection)算法結合不同的收集算法處理不同區域。
1、算法思路
基於前面說的弱代理論,其實並沒有什麼新的思想;
只是根據對象存活週期的不同將內存劃分爲幾塊;
這樣就可以根據各個年代的特點採用最適當的收集算法;
一般把Java堆分爲新生代和老年代;
(A)、新生代
每次垃圾收集都有大批對象死去,只有少量存活;
所以可採用複製算法;
(B)、老年代
對象存活率高,沒有額外的空間可以分配擔保;
使用"標記-清理"或"標記-整理"算法;
結合上面對新生代的內存劃分介紹和上篇文章對Java堆的介紹,可以得出HotSpot虛擬機一般的年代內存劃分,如下圖:
2、優點
可以根據各個年代的特點採用最適當的收集算法;
3、缺點
仍然不能控制每次垃圾收集的時間;
4、應用場景
目前幾乎所有商業虛擬機的垃圾收集器都採用分代收集算法;
如HotSpot虛擬機中全部垃圾收集器:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1(也保留);
5、火車算法
火車算法也稱列車算法,是一種更徹底的分區域處理收集算法,是對分代收集算法的一個有力補充。
1、算法思路
在火車算法中,內存被分爲塊,多個塊組成一個集合。爲了形象化,一節車廂代表一個塊,一列火車代表一個集合,如下圖;
火車與車箱都按創建順序標號,每個車廂大小相等,但每個火車包含的車廂數不一定相等;
每節車箱有一個被記憶集合,而每輛火車的記憶集合是它所有車廂記憶集合的總和;
記憶集合由指向車箱中對象的引用組成,這些引用來自同一輛火車中序號較高的車箱中的對象,以及序號較高中的對象;
垃圾收集以車廂爲單位,整體算法流程如下:
(1)、選擇標號最小的火車;
(2)、如果火車的記憶集合是空的, 釋放整列火車並終止, 否則進行第三步操作;
(3)、選擇火車中標號最小的車廂;
(4)、對於車廂記憶集合的每個元素:
如果它是一個被根引用引用的對象, 那麼, 將拷貝到一列新的火車中去;
如果是一個被其它火車的對象指向的對象, 那麼, 將它拷貝到這個指向它的火車中去.;
假設有一些對象已經被保留下來了, 那麼通過這些對象可以觸及到的對象將會被拷貝到同一列火車中去;
如果一個對象被來自多個火車的對象引用, 那麼它可以被拷貝到任意一個火車去;
這個步驟中, 有必要對受影響的引用集合進行相應地更新;
(5)、釋放車廂並且終止;
收集過程會刪除一些空車箱和空車,當需要的時候也會創建一些車箱和火車,更多信息請參考:《編譯原理》第二版7.75"列車算法"、《漸進式地垃圾回收: 火車算法》;
執行過程如下圖:
2、優點
可以在成熟對象空間提供限定時間的漸近收集;
而不需要每次都進行一個大區域的垃圾回收過程;
即可以控制垃圾回收的時間,在指定時間內進行一些小區域的回收;
3、缺點
實現較爲複雜,如採用類似的算法的G1收集器在JDK7才實現;
一些場景下可能性價比不高;
4、應用場景
JDK7後HotSpot虛擬機G1收集器採用類似的算法,能建立可預測的停頓時間模型;
到這裏,我們大體瞭解Java虛擬機垃圾回收的幾種常見算法,後面我們將分別去了解JVM垃圾收集器、以及相關調優方法……
【參考資料】
1、《編譯原理》第二版 第7章
2、《深入理解Java虛擬機:JVM高級特性與最佳實踐》第二版 第3章
3、《The Java Virtual Machine Specification》Java SE 8 Edition:https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
4、《Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide》:http://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/index.html
5、《Memory Management in the Java HotSpot™ Virtual Machine》:http://www.oracle.com/technetwork/java/javase/tech/memorymanagement-whitepaper-1-150020.pdf
6、HotSpot虛擬機參數官方說明:http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
7、《Thinking in Java》第四版 5.5 清理:終結處理和垃圾回收;
8、漸進式地垃圾回收: 火車算法:http://nileader.blog.51cto.com/1381108/402609
————————————————
原文鏈接:https://blog.csdn.net/tjiyu/article/details/53983064