JAVA GC 原理詳解

大多數狀況下咱們對GC的瞭解都只是淺層含義上的,下面咱們來詳細講解下內部的一些實現原理。
講解GC以前,咱們得先了解下JVM的內存結構,才能讓咱們理解GC致使是幹嗎的。算法

一.JVM 內存結構

JVM內存結構由5個部分組成,分別以下數組

1. 程序計數器(Program Conuter Register)

一塊較小的內存空間,它是當前線程執行字節碼的行號指示器,字節碼解釋工做器就是經過改變這個計數器的值來選取下一條須要執行的指令。它是線程私有的內存,也是惟一一個沒有OOM異常的區域。服務器

2. Java虛擬機棧區(Java Virtual Machine Stacks)

也就是一般所說的棧區,它描述的是Java方法執行的內存模型,每一個方法被執行的時候都建立一個棧幀(Stack Frame),用於存儲局部變量表、操做數棧、動態連接、方法出口等。每一個方法被調用到完成,至關於一個棧幀在虛擬機棧中從入棧到出棧的過程。此區域也是線程私有的內存,可能拋出兩種異常:若是線程請求的棧深度大於虛擬機容許的深度將拋出StackOverflowError;若是虛擬機棧能夠動態的擴展,擴展到沒法動態的申請到足夠的內存時會拋出OOM異常。多線程

3. 本地方法棧(Native Method Stacks)

本地方法棧與虛擬機棧發揮的做用很是類似,區別就是虛擬機棧爲虛擬機執行Java方法,本地方法棧則是爲虛擬機使用到的Native方法服務。併發

4. 堆區(Heap)

全部對象實例和數組都在堆區上分配,堆區是GC主要管理的區域。堆區還能夠細分爲新生代、老年代,新生代還分爲一個Eden區和兩個Survivor區。此塊內存爲全部線程共享區域,當堆中沒有足夠內存完成實例分配時會拋出OOM異常。線程

5. 方法區(Method Area)

方法區也是全部線程共享區,用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯後的代碼等數據。GC在這個區域不多出現,這個區域內存回收的目標主要是對常量池的回收和類型的卸載,回收的內存比較少,因此也有稱這個區域爲永久代(Permanent Generation)的。當方法區沒法知足內存分配時拋出OOM異常。設計


二.GC 原理

針對GC的原理機制,主要搞清楚下面三個問題。code

  1. 何時回收?
  2. 哪些須要回收?
  3. 怎麼回收?

1. 何時回收?

1.對象優先分配到新生代的Eden區,當不夠空間的時候進行一次Minor GC,清理頻率很高。
2.Full GC發生在老年代,當不夠空間的時候進行一次Full GC,伴隨着也會進行一次Minor GC。
3.進行Minor GC時,會判斷每次變成晉升到老年代的對象平均值是否大於老年代剩餘空間,若是大於,則進行一次Full GC,若是小於就會去判斷HandlePromotionFailure設置是否容許擔保失敗,若是容許,則進行Minor GC,不容許則改成Full GC。對象

上面提到GC主要管理的是堆區,堆區主要分爲`新生代`和`老年代`
* 【新生代】分爲一個Eden和兩個Survivor區。新new的對象都放在這裏,很快消亡。
* 【老年代】新new的大對象直接丟到這裏(爲了不在Eden區和兩個Survivor區發生大量的內存拷貝),其他就是在新生代屢次回收沒被幹掉過來變成老傢伙的對象了。

2. 哪些須要回收?

當調用了finalize()方法後,則須要進行清理,具體場景如上。內存

* 什麼是finalize()方法?

每次進行GC以前系統都會調用一次finalize()方法,用以清理全部活動而且釋放資源。

* 何時調用finalize()方法?

1.GC調用以前,例如運行System.gc();(調用System.gc()只是建議JVM去執行,是否執行還得JVM去判斷)
2.程序退出時,每一個對象都會調用finalzie
3.顯式調用finalize

3. 怎麼回收?

JVM會根據不一樣的收集器使用不一樣的算法組合來達到回收的效果

### 垃圾收集算法

* mark-sweep(標記-清除)- 標記全部須要回收的對象,在標記完成後統一回收這些對象。

缺點:1.標記和清除兩個過程的效率都不高。2.標記清除會產生大量不連續的內存碎片。

* copying(複製)- 主要用來回收新生代

新生代分爲一個Eden區、兩個Survivor區(Survivor0、Survivor1),Eden和Survivor默認8:1。回收時先把Eden存活對象複製到Survivor0區,清空Eden區,當Survivor0區滿了之後,把Eden和Survivor0區的存活對象複製到Survivor1區,清空Eden區和Survivor0區,以後交換Survivor0和Survivor1區,保持Survivor1區是空的,如此往復

* mark-compact(標記-整理)

主要用來回收老年代。標記須要回收的對象,將其餘存活的對象都向一端移動,而後直接清理掉端邊界之外的內存。

* generational collection(分代)

目前經常使用的收集算法,區分新生代和老年代作不一樣的算法收集。針對新生代,只有少許存活,選用複製算法。針對老年代,存活率高,沒有額外的空間對它進行分配擔保,就必須使用「標記-清理」或者「標記-整理」算法來進行回收。

--------

### 垃圾收集器

* Serial 、Serial Old 收集器 [-XX:+UseSerialGC,使用 Serial + Serial Old 組合回收]

適合單處理器系統,而且在進行垃圾回收的時候會暫停其餘全部的工做線程(stop the world),對於多處理器的系統來講是災難

* ParNew 收集器 [-XX:UseParallelGC,使用 Parallel Scavenge + Serial Old 組合回收]

serial 收集器的多線程版本。ParNew是許多運行在Server模式下的虛擬機中首選的新生代收集器,除了Serial收集器外,只有它能與CMS收集器配合工做

* Parallel Scavenge 、Parallel Old 收集器 [-XX:GCTimeRatio,-XX:MaxGCPauseMillis]

經過兩個參數GCTimeRatio和MaxGCPauseMillis,儘量縮短垃圾收集器用戶線程的停頓時間,從而達到一個可控制的吞吐量。

* CMS (Concurrent Mark Sweep)收集器 [-XX:UseConcMarkSweepGC,使用 ParNew + CMS + Serial Old 組合回收]

以獲取最短回收停頓時間爲目標的收集器。

步驟

1.初始標記(CMS initial mark),標記GC Roots能直接關聯到的對象,速度很快
2.併發標記(CMS concurrent mark),進行GC Roots Tracing
3.從新標記(CMS remark),從新標記階段是爲了修正併發標記期間因用戶程序繼續運做而致使變更的標記記錄,比並發標記時間短
4.併發清除(CMS concurrent sweep)並行刪除

缺點
1. 比較消耗CPU資源,默認啓動回收線程數是(CPU數量+3)/4。
2. CMS收集器沒法處理浮動垃圾(CMS清理階段用戶線程還運行着,伴隨生成的新垃圾只能在下次GC再清理掉),可能出現「Concurrent Mode Failure」而致使另外一次Full GC的產生。能夠經過-XX:CMSInitiatingOccupancyFraction來調節。
3. 標記-清除會致使內存碎片而致使觸發Full GC(切換到Serial Old收集器收集老年代)。能夠經過-XX:UseCMSCompactAtFullCollection、-XX:CMSFullGCsBeforeCompaction來調節。

* G1(Garbage-First) 收集器 [-XX:+UseG1GC]

Java堆的內存分佈和其餘收集器有很大不一樣,它將整個Java堆劃分爲多個大小相等的獨立區域`Region`,老年代和新生代再也不物理隔離,而是一部分`Region`的集合。G1設計初衷是爲了縮短大堆(>4GB)時的停頓時間。它會跟蹤各個Region的垃圾堆積價值大小,後臺維護一個優先列表,每次根據容許的收集時間,優先回收價值最大的`Region`。

特色
1.併發和並行
2.分代收集
3.空間整合
4.可預測的停頓

步驟
1.初始標記(Initial Marking)
2.併發標記(Concurrent Marking)
3.最終標記(Final Marking)
4.篩選回收(Live Data Counting and Evacuation)

補充:

一、並行Parallel-XX:+UseParalleGC,追求吞吐量
多條垃圾收集線程並行工做,但此時用戶線程仍然處於等待狀態
二、併發ConcurrentUseConcMarkSweepGC,追求響應速度
指用戶線程與垃圾收集線程同時執行(但並不必定是並行的,可能會交替執行),用戶程序在繼續運行,而垃圾收集程序運行於另外一個CPU上

串行處理器: Serial
--適用狀況:數據量比較小(100M左右);單處理器下而且對響應時間無要求的應用。
--缺點:只能用於小型應用
並行處理器:UseParalleGC
--適用狀況:「對吞吐量有高要求」,多CPU、對應用響應時間無要求的中、大型應用。舉例:後臺處理、科學計算。
--缺點:應用響應時間可能較長
併發處理器:UseConcMarkSweepGC--適用狀況:「對響應時間有高要求」,多CPU、對應用響應時間有較高要求的中、大型應用。舉例:Web服務器/應用服務器、電信交換、集成開發環境。

相關文章
相關標籤/搜索