1. 程式人生 > >JVM:GC-常用演算法理解

JVM:GC-常用演算法理解

標記-清除

實現原理:
1、標記:標記出所有需要被回收的物件
2、清除:標記完成後,統一回收所有被標記的物件

圖示:
在這裡插入圖片描述

缺點:
1、效率:標記和清除的效率都不高
2、空間:標記清除後會有大量不連續的碎片空間存在,當分配一個大物件時,很有可能因為找不到足夠大的連續空間而導致第二次GC

複製演算法

實現原理:將一塊大記憶體分為兩塊一樣大小的小記憶體,每次只使用一塊,當這一塊的記憶體用完,就會把還存活的物件全部移動到另一塊記憶體【移動堆頂指標,按序分配】,然後把已經使用過的記憶體空間一次性清理。

圖示:
在這裡插入圖片描述

優點:效率高,無需考慮碎片空間
缺點:可用記憶體變成原來的一半。在存活率較高的時候,有大量的複製操作,導致效率下降

標記-整理

實現原理:
1、標記:標記出所有需要回收的物件
2、整理:把存活的物件往一端移動,清理邊界之外的記憶體

圖示:
在這裡插入圖片描述

優點:效率高、沒有記憶體碎片,相對於複製演算法而言,可以使用到一整塊記憶體,而不是一半。

分代收集

原理:根據物件存活時間的長短,分配不同的記憶體區域。一般分為新生代、年老代。

新生代:新生代在每次GC都會有大量物件死去,只有少量物件存活,適用於複製演算法,只需付出極少的複製成本。
年老代:物件存活率高,而且沒有額外空間做擔保,所以一般使用 標記-清除 或者標記-整理。

HotSpot演算法實現

1、為什麼有stop the world?
實現垃圾回收的第一步是判斷哪些物件可以被回收,hotspot通過可達性分析去判斷,這項工作必須在一個能確保一致性的快照中進行,所謂的一致性是指在可達性分析的過程中,不能出現引用關係變化的情況,這點就導致GC的過程中必須要停頓所有的JAVA執行執行緒。

2、如何優化stop the world?
設想一下,如果可達性分析真的要去逐個檢查所有物件的引用,那麼勢必是非常浪費時間的,而且這個時間絕對不是使用者可以接受的。
實際上,虛擬機器確實不需要去檢查每一個上下文和全域性的引用位置,虛擬機器是有辦法直接得知那個位置有什麼引用。這就是所謂的準確式GC.

3、準確式GC的實現原理?
在HotSpot的實現中,使用了一組稱為OopMap的資料結構,當類載入完成後,OopMap就會把物件某個偏移量上是什麼型別的資料計算出來了。

如果所有會導致引用關係變化的指令都生成一個OopMap,那麼顯然要生成的OopMap太多了,那會需要大量額外的空間,導致GC的成本增大。
所以事實上,JVM也並沒有為每一個指令生成OopMap,
只是在稱為安全點的位置才會生成OopMap。

4、安全點的選取
目標:一般以是否能讓程式長時間執行為標誌設定安全點
舉例:方法呼叫、迴圈跳轉、異常跳轉

5、如何在GC時讓所有執行緒都跑到安全點在暫停?
搶先式中斷:
在GC發生時,中斷所有JAVA執行緒,當發現有執行緒不在安全點,就讓他跑到安全點在暫停。
主動式中斷:
就是事先設定一個標誌,所有執行緒去輪詢這個標誌,當為true時,則中斷掛起,輪詢標誌的地方和安全點重合。

6、安全區域
在一段程式碼的任何一個地方,都不會發生引用關係的改變,就稱之為安全區域。
當發生GC時,JVM不需要管處於安全區域的執行緒。
當處於安全區域的執行緒要出安全區域時會先判斷根節點列舉獲取整個GC過程是否完成,如果沒完成就繼續等待直到收到可以離開安全區域的訊號為止。