1. 程式人生 > >JVM垃圾回收(GC)

JVM垃圾回收(GC)

### JVM垃圾回收(GC) #### 1. 判斷物件是否可以被回收 - 引用計數法:每個物件有一個引用計數屬性,新增一個引用時計數加1,引用釋放時計數減1,計數為0時可以回收。此方法簡單,但**無法解決物件相互迴圈引用的問題**。 ```java // 迴圈引用 Node a=new Node(); Node b=new Node(); a.next=b; b.next=a; ``` - 可達性分析:從GC Roots開始向下搜尋,搜尋所走過的路徑稱為引用鏈。當一個物件到GC Roots沒有任何引用鏈時,則證明此物件時不可用的,可以被回收。 為了避免物件相互迴圈引用的問題,JVM中使用可達性分析判斷物件是否可以被回收。 #### 2. 四種引用 ##### 2.1 強引用(StrongReference) 大部分引用都是強引用,是使用最普遍的引用。**強引用不會被垃圾回收器回收,始終是可達狀態。**當記憶體空間不足時,JVM寧可丟擲OOM異常,使程式異常終止,也不會通過回收具有強引用的物件來解決記憶體不足的問題。這是造成Java記憶體洩漏的重要原因之一。(聯絡ThreadLocal例子) ##### 2.2 軟引用(SoftReference) 對於具有軟引用的物件,當記憶體空間足夠時,垃圾回收器不會回收它,若記憶體空間不夠了,就會回收這些物件的記憶體。軟引用可以用來實現記憶體敏感的快取記憶體。 ##### 2.3 弱引用(WeakReference) 只要垃圾回收機制執行並發現了具有弱引用的物件,不管當前記憶體空間是否足夠,都會回收該物件的記憶體。垃圾回收執行緒的優先順序很低,不一定很快發現只具有弱引用的物件。 ##### 2.4 虛引用(PhantomReference) 主要作用是用於**跟蹤物件被垃圾回收的活動**。不能單獨使用,必須與引用佇列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個物件時,如果發現它具有虛引用,就會在回收物件的記憶體前把這個虛引用加入到與之關聯的引用佇列中。程式可以通過判斷引用佇列中是否已經加入虛引用來了解被引用的物件是否要被垃圾回收。 #### 3. 判斷廢棄常量和無用的類 **廢棄常量**:執行時常量池主要回收廢棄常量。如果當前沒有任何物件引用該常量,就說明該常量是廢棄常量。 **無用的類**:需要同時滿足3個條件。 - 該類的所有例項都已經被回收,即堆中不存在該類的任何例項。 - 載入該類的ClassLoader已經被回收 - 該類對於的java.lang.Class物件沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。 #### 4. 垃圾收集演算法 ##### 4.1 標記-清除演算法(Mark-Sweep) **原理**:首先標記出可以回收的物件,在標記完成後統一回收所有被標記的物件。 ![image-20200810215551792](https://chiaki.oss-cn-beijing.aliyuncs.com/image-20200810215551792.png) **特點**:**記憶體碎片化嚴重、效率低**。 ##### 4.2 複製演算法(Copying) **原理**:按記憶體容量將記憶體劃分為大小相同的兩塊。每次只使用其中的一塊,當這一塊記憶體滿了之後,將存活的物件複製到未使用的一塊中,然後把使用的那一塊一次清理。 ![](https://chiaki.oss-cn-beijing.aliyuncs.com/image-20200810232555360.png) **特點:不易產生記憶體隨便,但效率大大降低。** ##### 4.3 標記-整理演算法(Mark-Compact) **原理**:首先標記出可以回收的物件,然後將存活物件移動至記憶體的一端,然後清除掉邊界外的物件。 ![image-20200810220445973](https://chiaki.oss-cn-beijing.aliyuncs.com/image-20200810220445973.png) **特點:根據老年代特點提出的一種標記演算法。** ##### 4.4 分代收集演算法 當前虛擬機器的垃圾收集都採用分代收集演算法。 在**新生代**,每次收集都會有大量物件死去,所以採用**複製演算法**,只需復出少了物件的複製成本就可以完成每次垃圾收集。 在**老年代**,物件存活機率比較高,每次垃圾回收是時只有少量物件需要被回收,因此採用**標記-整理演算法**進行垃圾收集。 #### 5. 垃圾收集器 JVM針對新生代和老年代分別提供了不同的垃圾收集器。 ![image-20200810221554182](https://chiaki.oss-cn-beijing.aliyuncs.com/image-20200810221554182.png) ##### 5.1 Serial收集器(單執行緒+複製演算法) Serial收集器是最基本的垃圾收集器。Serial是單執行緒的收集器,只會使用一條垃圾收集執行緒去完成垃圾收集工作,同時在進行垃圾收集工作時不許暫停其他所有的工作執行緒("Stop the World"),直到收集結束。 新生代採用複製演算法,老年代採用標記-整理演算法。 Serial收集器簡單高效,對於限定單個CPU環境來說沒有執行緒互動的開銷,可以獲得最高的單執行緒垃圾收集效率,因此Serial垃圾收集器時JVM執行在Client模式下預設的新生代垃圾收集器。 ![image-20200810223253078](https://chiaki.oss-cn-beijing.aliyuncs.com/image-20200810223253078.png) ##### 5.2 ParNew收集器(Serial+多執行緒) ParNew收集器是Serial收集器的多執行緒版本(多執行緒併發),除了使用多執行緒進行垃圾收集外,其餘行為和Serial收集器完全一樣。 新生代採用複製演算法,老年代採用標記-整理演算法。 ParNew收集器是執行在Server模式下的JVM的首要選擇,除了Serial收集器,只有它能與CMS收集器配合工作。 ![image-20200810223727906](https://chiaki.oss-cn-beijing.aliyuncs.com/image-20200810223727906.png) ##### 5.3 Parallel Scavenge收集器 與ParNew收集器類似,但Parallel Scavenge收集器的關注點是吞吐量(高效率地利用CPU)。CMS等垃圾收集器地關注點是使用者執行緒的停頓時間(提高使用者體驗)。所謂吞吐量就是CPU中用於執行使用者程式碼的時間與CPU總消耗時間的比值。 Parallel Scavenge提供了兩個引數用於精確控制吞吐量,分別是控制最大垃圾收集停頓時間的`-XX: MaxGCPauseMillis`引數以及直接設定吞吐量大小的`-XX: GCTimeRatio`引數。 ##### 5.4 Serial Old收集器(單執行緒+標記-整理演算法) Serial收集器的老年代版本。它具有兩大用途:一種是在JDK1.5及以前的版本中與Parallel Scavenge收集器搭配使用,另一種是作為CMS收集器的後備方案。 ##### 5.5 Parallel Old收集器(多執行緒+標記-整理演算法) Parallel Scavenge收集器的老年代版本,使用多執行緒和標記-整理演算法。在注重吞吐量和CPU資源的場合,可以優先考慮Parallel Scavenge收集器和Parallel Old收集器。 ##### 5.6 CMS收集器(多執行緒+標記-清除演算法) CMS(Concurrent Mark Sweep)收集器是一種**以獲取最短回收停頓時間為目標**的收集器,非常符合在注重使用者體驗的應用上使用。 CMS收集器是第一款真正意義上的併發收集器,第一次實現了讓垃圾回收執行緒與使用者執行緒(基本上)同時工作。CMS收集器是基於**標記-清除演算法**的。其執行過程包括四個步驟: ![image-20200810230029242](https://chiaki.oss-cn-beijing.aliyuncs.com/image-20200810230029242.png) - **初始標記**:**暫停所有其他執行緒**,並記錄下直接與GC Roots相連的物件,速度很快; - **併發標記**:同時開啟GC和使用者執行緒,用一個閉包結構去記錄可達物件。但在這個階段結束,這個閉包結構並不能保證包含當前所有的可達物件。因為使用者執行緒可能會不斷地更新引用域,所以GC執行緒無法保證可達性分析的實時性,因此這個演算法裡會跟蹤記錄這些發生引用更新的地方。該階段**無需暫停工作執行緒**; - **重新標記**:重新標記階段就是為了修正併發標記期間因為使用者程式繼續執行而導致標記產生變動的那一部分物件的標記記錄,這個階段的停頓時間一般會比初始標記階段的時間稍長,遠遠比並發標記近階段的時間短。該階段仍需要**暫停所有工作執行緒**,; - **併發清除**:開啟使用者執行緒,同時GC執行緒開始清除GC Roots不可達物件,**無需暫停工作執行緒**。 優點:**併發收集、低停頓**。 缺點:對CPU資源敏感;無法處理浮動垃圾;使用的"標記-清除"會導致收集結束時產生大量記憶體碎片。 ##### 5.7 G1收集器 G1(Garbage First)是面向伺服器的垃圾收集器,主要針對配備多核處理器及大容量記憶體的機器,**以極高概率滿足GC停頓時間要求的同時還具備高吞吐量效能特徵**。 特點: - **並行與併發** - **分代收集**:可以獨立管理整個GC堆,但也保留了分代的概念; - **空間整合**:基於標記-整理演算法,不產生記憶體碎片; - **可預測的停頓**:相比於CMS,G1可以能建立可預測的停頓時間模型,在不犧牲吞吐量的前提下實現低停頓的垃圾回收。 G1收集器執行步驟大致分為:**初始標記;併發標記;最終標記;篩選回收**。 **G1收集器避免全區域垃圾收集,把堆記憶體劃分為大小固定的幾個獨立區域,並且跟蹤這些區域的垃圾收集進度,同時在後臺維護一個優先順序列表,每次根據所允許的收集時間,優先回收垃圾最多的區域。區域劃分和優先順序區域回收機制,確保G1收集器可以在有限時間獲得最高的垃圾收集效