Java虛擬機器 垃圾收集演算法及HotSpot演算法實現

來源:互聯網
上載者:User

標籤:

垃圾收集演算法

一般來說,垃圾收集演算法分為四類:

標記-清除演算法

 

最基礎的演算法便是標記-清除演算法(Mark-Sweep)。演算法分為“標記”和“清除”兩個階段:首先標記處需要收集的對象,在標記完成之後,再統一回收所有被標記的對象。

這是最簡單的一種演算法,但是缺點也是很明顯的:一個是效率問題,標記和清除效率都不高。二是空間問題,清除之後會產生大量的空間片段,導致之後分配大對象找不到足夠的連續對象而不得不觸發另一次垃圾收集動作。演算法執行過程如。

 

 

複製演算法

 

複製演算法(Copying)將可用記憶體按照容量大小分成相等的兩份,每次只使用一半。當這一塊記憶體用完了,就會將還存活的對象複製到另一塊記憶體上,然後將之前的那塊記憶體清空。優點是解決了空間片段的問題,而且分配新對象的時候順序分配,實現簡單,運行高效。缺點是記憶體減小了一半。演算法如下。

現在的商業虛擬機器都採用這種收集演算法來回收新生代。由於新生代對象死亡率較高,所以可以將記憶體分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和一塊Survivor。當回收時,將Eden和一塊Survivor中還存活的對象複製到另一塊Survivor上,然後清理掉Eden和之前使用的Survivor空間。HotSpot虛擬機器預設Eden和Survivor比例為8:1,也就是只有10%的記憶體會被“浪費”。young 區和old 區使用的回收對象演算法不一樣,因為回收young 區滿了需要回收時,Old不需要被回收,而當Old區滿了要回收對象時,整個記憶體堆都要清理,而且使用者可以設定 young區和old區的回收是多線程還是單線程的,所以設計者是希望對象能夠多點時間留在young 區,以提高回收對象的效率。設計成From 和 To 兩個平行的區,我覺得是為了篩選真正符合old區的要求的對象(即需要長時間持有的引用的對象),然後再將他們放入old區。 

標記-整理演算法

複製演算法在對象存活率較高的情況下,效率會變低。而且浪費了50%的空間。

根據老年代的特點,有人提出了另外一種“標記-整理”演算法(Mark-Compact)。演算法的也分為標記和整理兩個階段。標記和“標記-清除”演算法的標記過程一樣。當標記完成之後,並不直接對可回收對象進行整理,而是所有存活的對象整理成連續的,然後清理掉剩餘的空間。演算法如下。

分代收集演算法

當前商業虛擬機器都採用“分代收集”(Generational Collection)演算法,根據對象存活的周期不同將記憶體劃分為幾塊。一般是將Java堆分為新生代和老年代,這樣就可以根據各個年代的特點採用最適當的收集演算法。新生代採用複製演算法,年老帶採用標記-清理或者標記-整理演算法。

 

HotSpot演算法實現枚舉根節點

在可達性分析中,可以作為GC Roots的節點有很多,但是現在很多應用僅僅方法區就有上百MB,如果逐個檢查的話,效率就會變得不可接受。

而且,可達性分析必須在一個一致性的快照中進行-即整個分析期間,系統就像凍結了一樣。否則如果一邊分析,系統一邊動態表化,得到的結果就沒有準確性。這就導致了系統GC時必須停頓所有的Java執行線程。

目前主流Java虛擬機器使用的都是準確式GC,所以當執行系統都停頓下來之後,並不需要一個不漏的檢查完所有執行內容和全域的引用位置,虛擬機器應該有辦法直接知道哪些地方存放著對象引用。在HotSpot實現中,使用一組稱為OopMap的資料結構來達到這個目的。OopMap會在類載入完成的時候,記錄對象內什麼位移量上是什麼類型的資料,在JTI編譯過程中,也會在特定的位置記錄下棧和寄存器哪些位置是引用。這樣,在GC掃描的時候就可以直接得到這些資訊了。

安全點

可能導致參考關聯性變化,或者說OopMap內容變化的指令非常多,HotSpot並不會為每條指令都產生OopMap,只是在特定的位置記錄了這些資訊,這些位置成為“安全點”(SafePoint)。程式執行時只有在達到安全點的時候才停頓開始GC。一般具有較長已耗用時間的指令才能被選為安全點,如方法調用、迴圈跳轉、異常跳轉等。

接下來要考慮的便是,如何在GC時保證所有的線程都“跑”到安全點上停頓下來。這裡有兩種方案:搶先式中斷(Preemptive Suspension)和主動式中斷(Voluntary Suspension)。

搶先式中斷會把所有線程中斷,如果某個線程不在安全點上,就恢複讓它跑到安全點上。幾乎沒有虛擬機器採用這種方式。

主動式中斷思想是設立一個GC標誌,各個線程會輪詢這個標誌並在需要時自己中斷掛起。這樣,標誌和安全點是重合的。

安全區域

Safepoint機制可以保證某一程式在啟動並執行時候,在不長的時間裡就可以進入GC的Safepoint。但是如果程式沒有分配CPU時間,例如處於Sleep狀態或者Blocked狀態,這時候線程無法響應JVM的插斷要求。對於這種情況,只能用安全區域(Safe Region)來解決。

安全區域是指在一段程式碼片段之中,參考關聯性不會發生變化。在這個地區中任意地方開始都是安全的。線上程執行到Safe Region中的代碼時,就標記自己已經進入了Safe Region,這樣JVM在發起GC時就跳過這些線程。線上程要離開Safe Region時,它要檢查系統是否已經完成了枚舉(或GC過程),如果完成了線程就繼續執行,否則就等待。

Java虛擬機器 垃圾收集演算法及HotSpot演算法實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.