JVM 垃圾回收器詳解

 小結:java

  • 新生代    串行Serial            並行 Parallel(關注吞吐量)           並行ParNew
  • 老年代    串行 Serial Old     並行Parallel Old(關注吞吐量)     併發CMS(關注停頓時間)
  • 新生代:複製算法             老年代 :標記-整理算法(CMS:標記-清除,能夠設置參數設置在每次Full GC  後者幾回Full GC後進行內存碎片的壓縮整理)
  • G1收集器基於標記-整理算法實現,也就是說不會產生內存碎片。G1收集器進行收集的範圍是個Java(包括新生代,老年代)
  • 吞吐量:運行代碼時間/(運行代碼時間+GC收集時間)。GC時間縮短是以犧牲吞吐量和新生代空間來獲取的:系統把新生代調小一些,致使垃圾收集發生得更頻繁一些,這樣停頓時間的確降低了,可是吞吐量也降低了。

 

 


             

上面有7中收集器,分爲兩塊,上面爲新生代收集器,下面是老年代收集器。若是兩個收集器之間存在連線,就說明它們能夠搭配使用。算法

1, 串行回收器

這裏寫圖片描述

1.1, 新生代串行回收器Serial

(1)特色: 
  –它僅僅使用單線程進行垃圾回收 
  –它是獨佔式的垃圾回收 
  –進行垃圾回收時, Java應用程序中的線程都須要暫停(Stop-The-World) 
  –使用複製算法 
  –適合CPU等硬件不是很好的場合 
(2)設置參數: 
  -XX:+UseSerialGC 指定新生使用新生代串行收集器和老年代串行收集器, 當以client模式運行時, 它是默認的垃圾收集器緩存

 

1.2, 老年代串行回收器Serial Old

(1)特色: 
  –同新生代串行回收器同樣, 單線程, 獨佔式的垃圾回收器 使用標記-整理算法
  –一般老年代垃圾回收比新生代回收要更長時間, 因此可能會使應用程序停頓較長時間 多線程

(2)設置參數: 
  -XX:+UseSerialGC 新生代, 老年代都使用串行回收器 
  -XX:+UseParNeGC 新生代使用ParNew回收器, 老年代使用串行回收器 
  -XX:+UseParallelGC 新生代使用ParallelGC回收器, 老年代使用串行回收器併發


 

2, 並行回收器

這裏寫圖片描述

2.1, 新生代ParNew回收器

(1)特色: 
  –將串行回收多線程化, 
  –使用複製算法 
  –垃圾回收時, 應用程序仍會暫停, 只不過因爲是多線程回收, 在多核CPU上,回收效率會高於串行回收器, 反之在單核CPU, 效率會不如串行回收器 
(2)設置參數: 
  -XX:+UseParNewGC 新生代使用ParNew回收器, 老年代使用串行回收器 
  -XX:+UseConcMarkSweepGC 新生代使用ParNew回收器, 老年代使用CMS回收器 
  -XX:ParallelGCThreads=n 指回ParNew回收器工做時的線程數量, cpu核數小時8時, 其值等於cpu數量, 高於8時,可使用公式(3+((5*CPU_count)/8))oracle

 

2.2, 新生代Parallel回收器

(1)特色: 
  –同ParNew回收器同樣, 不一樣的地方在於,它很是關注系統的吞吐量(經過參數控制) 
  –使用複製算法 
  –支持自適應的GC調節策略函數

(3)設置參數:

  -XX:+UseParallelGC  新生代用ParallelGC回收器, 老年代使用串行回收器 
  -XX:+UseParallelOldGC  新生代用ParallelGC回收器, 老年代使用ParallelOldGC回收器系統吞吐量的控制: 
  -XX:MaxGCPauseMillis=n(單位ms)   設置垃圾回收的最大停頓時間, 
  -XX:GCTimeRatio=n(n在0-100之間)  設置吞吐量的大小, 假設值爲n, 那系統將花費不超過1/(n+1)的時間用於垃圾回收 
  -XX:+UseAdaptiveSizePolicy  打開自適應GC策略, 在這種模式下, 新生代的大小, eden,survivior的比例, 晉升老年代的對象年齡等參數會被自動調整,以達到堆大小, 吞吐量, 停頓時間之間的平衡點性能

 

2.3, 老年代Parallel Old回收器

(1)特色: 
  –同新生代的ParallelGC回收器同樣, 是屬於老年代的關注吞吐量的多線程併發回收器 
  –使用標記壓縮算法, 
(2)設置參數: 
  -XX:+UseParallelOldGC  新生代用ParallelGC回收器, 老年代使用ParallelOldGC回收器, 是很是關注系統吞吐量的回收器組合, 適合用於對吞吐量要求較高的系統 
  -XX:ParallelGCThreads=n   指回ParNew回收器工做時的線程數量, cpu核數小時8時, 其值等於cpu數量, 高於8時, 可使用公式(3+((5*CPU_count)/8))優化


 

3, 老年代CMS回收器(Concurrent Mark Sweep,併發標記清除)

3.1, 老年代的併發回收器

 

CMS(Concurrent Mark Sweep)收集器是一種 以獲取最短回收停頓時間爲目標的收集器。CMS收集器是基於「標記-清除」算法實現的,整個收集過程大體分爲4個步驟:
①.初始標記(CMS initial mark)
②.併發標記(CMS concurrenr mark)
③.從新標記(CMS remark)
④.併發清除(CMS concurrent sweep)
     其中初始標記、從新標記這兩個步驟任然須要停頓其餘用戶線程。 初始標記僅僅只是標記出 GC ROOTS能直接關聯到的對象,速度很快, 併發標記階段是進行 GC ROOTS 根搜索算法階段,會斷定對象是否存活。而 從新標記階段則是爲了修正併發標記期間,因用戶程序繼續運行而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間會被初始標記階段稍長,但比並發標記階段要短。
     因爲整個過程當中耗時最長的併發標記和併發清除過程當中,收集器線程均可以與用戶線程一塊兒工做,因此總體來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發執行的。
CMS收集器的優勢:併發收集、低停頓,可是CMS還遠遠達不到完美,器主要有三個顯著缺點:
CMS收集器對CPU資源很是敏感。在併發階段,雖然不會致使用戶線程停頓,可是會佔用CPU資源而致使引用程序變慢,總吞吐量降低。CMS默認啓動的回收線程數是:(CPU數量+3) / 4。
CMS收集器沒法處理浮動垃圾,可能出現「Concurrent Mode Failure「,失敗後而致使另外一次Full  GC的產生。因爲CMS併發清理階段用戶線程還在運行,伴隨程序的運行自熱會有新的垃圾不斷產生,這一部分垃圾出如今標記過程以後,CMS沒法在本次收集中處理它們,只好留待下一次GC時將其清理掉。這一部分垃圾稱爲「浮動垃圾」。也是因爲在垃圾收集階段用戶線程還須要運行,
即須要預留足夠的內存空間給用戶線程使用,所以CMS收集器不能像其餘收集器那樣等到老年代幾乎徹底被填滿了再進行收集,須要預留一部份內存空間提供併發收集時的程序運做使用。在默認設置下,CMS收集器在老年代使用了68%的空間時就會被激活,也能夠經過參數-XX:CMSInitiatingOccupancyFraction的值來提供觸發百分比,以下降內存回收次數提升性能。要是CMS運行期間預留的內存沒法知足程序其餘線程須要,就會出現「Concurrent Mode Failure」失敗,這時候虛擬機將啓動後備預案:臨時啓用Serial Old收集器來從新進行老年代的垃圾收集,這樣停頓時間就很長了。因此說參數-XX:CMSInitiatingOccupancyFraction設置的太高將會很容易致使「Concurrent Mode Failure」失敗,性能反而下降。
最後一個缺點,CMS是基於「標記-清除」算法實現的收集器,使用「標記-清除」算法收集後,會產生大量碎片。空間碎片太多時,將會給對象分配帶來不少麻煩,好比說大對象,內存空間找不到連續的空間來分配不得不提早觸發一次Full  GC。爲了解決這個問題,CMS收集器提供了一個-XX:UseCMSCompactAtFullCollection開關參數,用於在Full  GC以後增長一個碎片整理過程,還可經過-XX:CMSFullGCBeforeCompaction參數設置執行多少次不壓縮的Full  GC以後,跟着來一次碎片整理過程。

(1)特色: 
  –是併發回收, 非獨佔式的回收器, 大部分時候應用程序不會中止運行 
  –針對年老代的回收器, 
  –使用併發標記清除算法, 所以回收後會有內存碎片, 可使參數設置進行內存碎片的壓縮整理 
  –ParallelGC和ParallelOldGC主要關注吞吐量, CMS主要關注系統停頓時間 
(2)CMS主要步驟: 
  1. 初始標記 
  2. 併發標記 
  3. 從新標記 
  4. 併發清除

spa

–>注:初始標記與從新標記是獨佔系統資源的,不能與用戶線程一塊兒執行,而其它階段則能夠與用戶線程一塊兒執行 
(3)設置參數: 
  -XX:-CMSPrecleaningEnabled  關閉預清理, 不進行預清理, 默認在併發標記後, 會有一個預清理的操做,可減小停頓時間 
  -XX:+UseConcMarkSweepGC  老年代使用CMS回收器, 新生代使用ParNew回收器 
  -XX:ConcGCThreads=n  設置併發線程數量, 
  -XX:ParallelCMSThreads=n  同上, 設置併發線程數量, 
  -XX:CMSInitiatingOccupancyFraction=n  指定老年代回收閥值, 即當老年代內存使用率達到這個值時, 會執行一次CMS回收,默認值爲68, 設置技巧: (Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100)>=Xmn 
  -XX:+UseCMSCompactAtFullCollection  開啓內存碎片的整理, 即當CMS垃圾回收完成後, 進行一次內存碎片整理, 要注意內存碎片的整理並非併發進行的, 所以可能會引發程序停頓 
  -XX:CMSFullGCsBeforeCompation=n  用於指定進行多少次CMS回收後, 再進行一次內存壓縮 
  -XX:+CMSParallelRemarkEnabled  在使用UseParNewGC 的狀況下, 儘可能減小 mark 的時間 
  -XX:+UseCMSInitiatingOccupancyOnly  表示只有達到閥值時才進行CMS回收

 

3.2, Class的回收(永久區的回收)

設置參數: 
  -XX:+CMSClassUnloadingEnabled  開啓回收Perm區的內存, 默認狀況下, 是須要觸發一次FullGC 
  -XX:CMSInitiatingPermOccupancyFraction=n  當永久區佔用率達到這個n值時,啓動CMS回收, 需上一個參數開啓的狀況下使用


 

4, G1回收器(jdk1.7後全新的回收器, 用於取代CMS)

  G1(Garbage First)收集器是JDK1.7提供的一個新收集器,G1收集器基於「標記-整理」算法實現,也就是說不會產生內存碎片。還有一個特色以前的收集器進行收集的範圍都是整個新生代或老年代,而G1將整個Java堆(包括新生代,老年代)。

(1)特色: 
  –獨特的垃圾回收策略, 屬於分代垃圾回收器, 
  –使用分區算法, 不要求eden, 年輕代或老年代的空間都連續 
  –並行性: 回收期間, 可由多個線程同時工做, 有效利用多核cpu資源 
  –併發性: 與應用程序可交替執行, 部分工做能夠和應用程序同時執行, 
  –分代GC: 分代收集器, 同時兼顧年輕代和老年代 
  –空間整理: 回收過程當中, 會進行適當對象移動, 減小空間碎片 
  –可預見性: G1可選取部分區域進行回收, 能夠縮小回收範圍, 減小全局停頓 
(2)G1的收集過程 
1. 新生代GC: 
2. 併發標記週期: 
  –初始標記新生代GC(此時是並行, 應用程序會暫中止)–>根區域掃描–>併發標記–>從新標記(此時是並行, 應用程序會暫中止)–>獨佔清理(此時應用程序會暫中止)–>併發清理 
3. 混合回收: 
  –這個階段即會執行正常的年輕代gc, 也會選取一些被標記的老年代區域進行回收, 同時處理新生代和年老輕 
4. 若須要, 會進行FullGC: 
  –混合GC時發生空間不足 
  –在新生代GC時, survivor區和老年代沒法容納倖存對象時, 
  –以上二者都會致使一次FullGC產生 
(3)設置參數: 
  -XX:+UseG1GC  打開G1收集器開關, 
  -XX:MaxGCPauseMillis=n  指定目標的最大停頓時間,任何一次停頓時間超過這個值, G1就會嘗試調整新生代和老年代的比例, 調整堆大小, 調整晉升年齡 
  -XX:ParallelGCThreads=n  用於設置並行回收時, GC的工做線程數量 
  -XX:InitiatingHeapOccpancyPercent=n  指定整個堆的使用率達到多少時, 執行一次併發標記週期, 默認45, 過大會致使併發標記週期遲遲不能啓動, 增長FullGC的可能, 太小會致使GC頻繁, 會致使應用程序性能有所降低


 

5, 其餘GC相關的設置

5.1, System.gc()

(1)禁用System.gc() 
  -XX:+DisableExplicitGC  禁止程序中調用System.gc(), 加了此參數, 程序如有調用, 返回的空函數調用 
   System.gc()的調用, 會使用FullGC的方式回收整個堆而會忽略CMS或G1等相關回收器 
(2)System.gc()使用併發回收 
  -XX:+ExplicitGCCinvokesConcurrent   使用併發方式處理顯示的gc, 即開啓後, System.gc()這種顯示GC纔會併發的回收, (CMS, G1)

 

5.2, 並行GC前額外觸發的新生代GC

(1)使用並行回收器(UseParallelGC或者UseParallelOldGC)時, 會額外先觸發一個新生代GC, 目的是儘量減小停頓時間 
(2)若不須要這種特性, 可使用如下參數去除 
  -XX:-ScavengeBeforeFullGC   即去除在FullGC以前的那次新生代GC, 本來默認值爲true 
  

 

5.3, 對象什麼時候進入老年代

(1)當對象首次建立時, 會放在新生代的eden區, 若沒有GC的介入,會一直在eden區, GC後,是可能進入survivor區或者年老代 
(2)當對象年齡達到必定的大小 ,就會離開年輕代, 進入老年代, 對象進入老年代的事件稱爲晉升, 而對象的年齡是由GC的次數決定的, 每一次GC,若對象沒有被回收, 則對象的年齡就會加1, 可使用如下參數來控制新生代對象的最大年齡: 
  -XX:MaxTenuringThreshold=n  假設值爲n , 則新生代的對象最多經歷n次GC, 就能晉升到老年代, 但這個必不是晉升的必要條件 
  -XX:TargetSurvivorRatio=n  用於設置Survivor區的目標使用率,即當survivor區GC後使用率超過這個值, 就可能會使用較小的年齡做爲晉升年齡 
(3)除年齡外, 對象體積也會影響對象的晉升的, 若對象體積太大, 新生代沒法容納這個對象, 則這個對象可能就會直接晉升至老年代, 可經過如下參數使用對象直接晉升至老年代的閾值, 單位是byte 
  -XX:PretenureSizeThreshold  即對象的大小大於此值, 就會繞過新生代, 直接在老年代分配, 此參數只對串行回收器以及ParNew回收有效, 而對ParallelGC回收器無效,

 

5.4, 在TLAB上分配對象(Thread Local Allocation Buffer, 線程本地分配緩存)

(1)TLAB: TLAB是一個線程專用的內存分配區域, 虛擬機爲線程分配空間, 針對於體積不大的對象, 會優先使用TLAB, 這個能夠加速對象的分配, TLAB是默認開啓的, 若要關閉可使用如下參數關閉 
  -XX:-UseTLAB  關閉TLAB 
  -XX:+UseTLAB  開啓TLAB, 默認也是開啓的 
  -XX:+PrintTLAB  觀察TALB的使用狀況 
  -XX:TLABRefillWasteFraction=n  設置一個比率n, 而refill_waste的值就是(TLAB_SIZE/n), 即TLAB空間較小, 大對象沒法分配在TLAB,因此會直接分配到堆上,TLAB較小也很容易裝滿, 所以當TLAB的空間不夠分配一個新對象, 就會考慮廢棄當前TLAB空間仍是直接分配到堆上, 就會使用此參數進行判斷, 小於refill_waste就容許廢棄, 而新建TLAB來分配對象,而大於refill_waste就直接在堆上分配, 默認是64 
  -XX:+ResizeTLAB  開啓TLAB自動調整大小, 默認是開啓的, 若要關閉把+號換成-號便可 
  -XX:TLABSize=n  設置一個TLAB的大小, 前提先關閉TLAB的自動調整

 

垃圾收集器參數總結

-XX:+<option> 啓用選項
-XX:-<option> 不啓用選項
-XX:<option>=<number> 
-XX:<option>=<string>

 

參數 描述

-XX:+UseSerialGC

Jvm運行在Client模式下的默認值,打開此開關後,使用Serial + Serial Old的收集器組合進行內存回收
-XX:+UseParNewGC 打開此開關後,使用ParNew + Serial Old的收集器進行垃圾回收
-XX:+UseConcMarkSweepGC 使用ParNew + CMS +  Serial Old的收集器組合進行內存回收,Serial Old做爲CMS出現「Concurrent Mode Failure」失敗後的後備收集器使用。
-XX:+UseParallelGC Jvm運行在Server模式下的默認值,打開此開關後,使用Parallel Scavenge +  Serial Old的收集器組合進行回收
-XX:+UseParallelOldGC 使用Parallel Scavenge +  Parallel Old的收集器組合進行回收
-XX:SurvivorRatio 新生代中Eden區域與Survivor區域的容量比值,默認爲8,表明Eden:Subrvivor = 8:1
-XX:PretenureSizeThreshold 直接晉升到老年代對象的大小,設置這個參數後,大於這個參數的對象將直接在老年代分配
-XX:MaxTenuringThreshold 晉升到老年代的對象年齡,每次Minor GC以後,年齡就加1,當超過這個參數的值時進入老年代
-XX:UseAdaptiveSizePolicy 動態調整java堆中各個區域的大小以及進入老年代的年齡
-XX:+HandlePromotionFailure 是否容許新生代收集擔保,進行一次minor gc後, 另外一塊Survivor空間不足時,將直接會在老年代中保留
-XX:ParallelGCThreads 設置並行GC進行內存回收的線程數
-XX:GCTimeRatio GC時間佔總時間的比列,默認值爲99,即容許1%的GC時間,僅在使用Parallel Scavenge 收集器時有效
-XX:MaxGCPauseMillis 設置GC的最大停頓時間,在Parallel Scavenge 收集器下有效
-XX:CMSInitiatingOccupancyFraction 設置CMS收集器在老年代空間被使用多少後出發垃圾收集,默認值爲68%,僅在CMS收集器時有效,-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSCompactAtFullCollection 因爲CMS收集器會產生碎片,此參數設置在垃圾收集器後是否須要一次內存碎片整理過程,僅在CMS收集器時有效
-XX:+CMSFullGCBeforeCompaction 設置CMS收集器在進行若干次垃圾收集後再進行一次內存碎片整理過程,一般與UseCMSCompactAtFullCollection參數一塊兒使用
-XX:+UseFastAccessorMethods 原始類型優化
-XX:+DisableExplicitGC 是否關閉手動System.gc
-XX:+CMSParallelRemarkEnabled 下降標記停頓
-XX:LargePageSizeInBytes 內存頁的大小不可設置過大,會影響Perm的大小,-XX:LargePageSizeInBytes=128m

 

 

Client、Server模式默認GC

 

  新生代GC方式 老年代和持久GC方式

Client

Serial 串行GC Serial Old 串行GC
Server Parallel Scavenge  並行回收GC Parallel Old 並行GC

 

Sun/oracle JDK GC組合方式

 
 
  新生代GC方式 老年代和持久GC方式

-XX:+UseSerialGC

Serial 串行GC Serial Old 串行GC
-XX:+UseParallelGC Parallel Scavenge  並行回收GC Serial Old  並行GC
-XX:+UseConcMarkSweepGC ParNew 並行GC CMS 併發GC 
當出現「Concurrent Mode Failure」時
採用Serial Old 串行GC
-XX:+UseParNewGC ParNew 並行GC Serial Old 串行GC
-XX:+UseParallelOldGC Parallel Scavenge  並行回收GC Parallel Old 並行GC
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
Serial 串行GC CMS 併發GC 
當出現「Concurrent Mode Failure」時
採用Serial Old 串行GC

 

 

轉自  http://blog.csdn.net/lghuntfor/article/details/51052737

 http://blog.csdn.net/java2000_wl/article/details/8030172

相關文章
相關標籤/搜索