原文地址:xeblog.cn/articles/24java
新生代均採用
複製
算法來回收內存。算法
最基本的、發展歷史最悠久的單線程的收集器。在進行垃圾收集時,必須暫停其它全部的工做線程(Stop The World),直到它收集結束。它是 JVM
運行在 Client
模式下的默認新生代收集器,它比其它單線程的收集器更簡單、更高效。可與 CMS 收集器
配合工做。bash
Serial 收集器
的多線程版本。它是許多運行在 Server
模式下的虛擬機首選的新生代收集器,在使用 -XX:+UseConcMarkSweepGC
選項後的默認新生代收集器,也能夠經過 -XX:+UseParNewGC
選項強制指定它。它除了是多線程收集以外,其它和 Serial 收集器
基本同樣,它默認開啓的收集線程數與 CPU
的數量相同,在 CPU
很是多的環境下,可經過 -XX:ParallelGCThreads
參數限制垃圾收集的線程數。可與 CMS 收集器
配合工做。多線程
並行的多線程收集器,它的目標是達到一個可控的吞吐量(吞吐量是 CPU
用於運行用戶代碼的時間與 CPU
總消耗時間的比值)。併發
吞吐量 = 運行用戶代碼的時間 / (運行用戶代碼的時間 + 垃圾收集時間)
複製代碼
高吞吐量能夠高效的利用 CPU
時間,儘快的完成程序的運算任務,主要適合在後臺運算而不須要太多交互的任務。Parallel Scavenge 收集器
提供了兩個參數用於精確控制吞吐量: -XX:MaxGCPauseMillis
和 -XX:GCTimeRatio
。性能
容許一個大於0的毫秒數,收集器將盡量保證內存回收花費時間不超過這個設定的值,它是以犧牲吞吐量和新生代空間來縮短 GC
停頓時間的。spa
容許一個大於0且小於100的整數,垃圾收集時間佔總時間的比率。線程
這是一個開關參數,當它打開後,就不須要手動指定新生代的大小(-Xmn),Eden
與 Survivor
區的比例(-XX:SurvivorRatio)、晉升老年代對象年齡(-XX:PretenureSizeThreshold)等細節參數了,虛擬機會根據當前系統的運行狀況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或最大的吞吐量。3d
老年代採用
標記-整理
或標記-清除
算法來回收內存。code
它是 Serial 收集器
的老年代版本,也是一個單線程收集器,使用 標記-整理
算法。這個收集器的主要意義也是在於給 Client
模式下的虛擬機使用,若是是在 Server
模式下,那麼它主要還有兩大用途:
JDK1.5
以及以前版本中與 Parallel Scavenge 收集器
搭配使用。CMS收集器
的後備預案,在併發收集發生 Concurrent Mode Failure
時使用。它是 Parallel Scavenge 收集器
的老年代版本,使用多線程和 標記-整理
算法。
它是一種併發的、以獲取最短回收停頓時間爲目標的收集器,使用 標記-清除
算法實現的。運行過程較爲複雜,整個過程分爲4個步驟:
初始標記、從新標記仍須要暫停其它全部的工做線程,初始標記僅僅只是標記一下 GC Roots
能直接關聯到的對象,速度很快。併發標記階段就是進行 GC Roots
的可達性分析過程,而從新標記階段則是爲了修正併發標記期間因用戶線程繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短。CMS 收集器
存在3個明顯的缺點:
CMS收集器
會佔用一部分線程而致使應用程序變慢,總吞吐量會下降。CMS
默認啓功的回收線程數是(CPU數量 + 3)/ 4
,至關於當 CPU
在4個以上時,併發回收時垃圾收集線程很多於 25%
的 CPU
資源,並隨着 CPU
數量的增長而降低。當 CPU
不足4個時,CMS
對用戶線程的影響就可能變得更大。CMS收集器
沒法處理浮動垃圾,可能出現 Concurrent Mode Failure
失敗而致使另外一次 Full GC
的產生。因爲 CMS
併發清除階段用戶線程還在運行着,伴隨程序運行天然就還會有新的垃圾不斷產生,這一部分垃圾出如今標記過程以後,CMS
沒法在當次收集中處理掉它們,只好留在下一次 GC
時再清理掉,這一部分垃圾就稱爲浮動垃圾。CMS收集器
使用的是 標記-清除
算法,因此垃圾回收後會產生大量的空間碎片。CMS
提供 -XX:+UseCMSCompactAtFullCollection
的開關參數(默認開啓),用於在 CMS
收集器頂不住要進行 Full GC
時開啓內存碎片的合併整理過程,這個過程是沒法併發執行的,雖然空間碎片沒了,可是停頓時間不得不變長。
G1收集器
是當今收集器技術發展的最前沿成果之一。
上面所介紹的收集器,都只是負責 Java堆
中的一部份內存(新生代或老年代),而 G1
就不一樣了,它全乾。
G1
將整個 Java堆
劃分爲多個大小相等的獨立區域(Region),雖然還保留有新生代和老年代的概念,可是這兩部份內存再也不是物理隔離的,它們都是一部分不須要連續的 Region
的集合了。
具有的特色:
G1
能充分利用多 CPU
、多核環境下的硬件優點,使用多個 CPU
來縮短 Stop The World
的停頓時間。G1
能夠不須要與其它收集器配合就能獨立管理整個 GC堆
,根據 分代收集
的概念採用不一樣的方式去處理。標記-整理
和 複製
算法,不會產生內存空間碎片。G1
能夠創建可預測的停頓時間模型,將垃圾收集消耗的時間限制在必定的時間內。G1
之因此可以創建可預測的停頓時間模型,是由於它能夠有計劃的避免在整個 Java堆
中進行全區域的垃圾收集。G1
經過跟蹤各個 Region
裏面的內存堆積的價值大小(回收所得到的空間大小以及回收所需時間的經驗值),在後臺維護一個優先回收隊列,每次根據容許的收集時間,優先回收價值最大的 Region
。這種使用 Region
劃份內存空間以及有優先級的區域回收方式,保證了 G1
收集器在有限的時間內能夠獲取儘量高的收集效率。
在 G1
收集器中,Region
之間的對象引用以及其它收集器中的新生代與老年代之間的對象引用,虛擬機都是使用 Remembered Set
來避免全堆掃描的。G1
中的每個 Region
都有一個與之對應的 Remembered Set
,在對 Reference
類型的數據進行寫操做的時間,虛擬機會產生一個屏障暫時中斷寫操做,而後檢查這個引用的對象是否處於不一樣的 Region
之中,若是是,就會經過 CardTable
把相關引用信息記錄到被引用對象所屬的 Region
的 Remembered Set
中。當進行內存回收時,在 GC Roots
的枚舉範圍內加入 Remembered Set
便可保證不對全堆掃描也不會有遺漏。
若是不計算維護 Remembered Set
的操做,G1
收集器的運行過程大體能夠分爲4個步驟:
初始標記階段只是簡單的標記一下 GC Roots
能直接關聯到的對象,而且修改TAMS(Next Top At Mark Start)的值,讓下一階段用戶程序併發運行時,能在正確可用的 Region
中建立新對象,這個階段須要停頓線程,但耗時很短。併發標記階段也是進行 GC Roots
的可達性分析過程,耗時很長可是可與用戶程序一塊兒工做。最終標記階段是爲了修正併發標記期間因用戶線程繼續運做而致使標記產生變更的那一部分對象的標記記錄,虛擬機將這段時間對象變化記錄在線程的 Remembered Set Logs
中,這個階段須要把 Remembered Set Logs
中的數據合併到 Remembered Set
裏,須要停頓線程,可是能夠並行執行。 最後的篩選回收階段會對 Region
的回收價值和成本進行排序,根據用戶所指望的 GC
停頓時間來制定回收計劃。
java -XX:+PrintCommandLineFlags -version
複製代碼
在終端執行上述命令後,便可查看 JVM
所使用的收集器。
-XX:+UseParallelGC : 是虛擬機運行在 Server
模式下的默認值,打開此開關後,使用 Parallel Scavenge + Serial Old (PS MarkSweep)
的收集器組合進行內存回收。