天天看點

JVM之GC垃圾回收全面解析(二)

上節介紹了GC相關概念,算法,和各版本HEAP結構,對GC有了認知。該節開始介紹GC收集器和具體優化。

GC收集器種類 (重點介紹了cms收集器和G1收集器)

 1. Serial:串行收集器,穩定高效停頓時長。新老都串行回收 -XX:+UseSerialGC

 2. ParNew: 并行收集器,新并行,老串行XX:+UseParNewGC

 3. Parallel: 并行收集器+串行老年代 XX:+UseParallelGC

 -XX:+UseAdaptiveSizePolicy 打開自适應GC政策, 在這種模式下, 新生代的大小, eden,survivior的比例, 晉升老年代的 對象年齡等參數會被自動調整,以達到堆大小,吞吐量, 停頓時間之間的平衡點

 4. Parallel:  并行收集器+并行老年代(throughput)  XX:+UseParallelOldGC

 -XX:MaxGCPauseMills,代表最大的GC線程占用的停頓時間,機關是毫秒   -XX:GCTimeRatio,吞吐量-垃圾收集時間占 總時間的比,預設99,允許1%時間做GC.

 如果GC很頻繁     GC的最大停頓時間變短,但吞吐量變小,

 如果GC次數很少   最大的停頓時間就會變長,但吞吐量增大

 5. CMS:并發收集器(Concurrent Mark Sweep) 針對老年代

 老年代使用CMS回收器, 新生代使用ParNew回收器;基于标記清除算法(不壓縮且

 産生記憶體碎片,弊端:碎片和浮動垃圾導緻另一次FULLGC)  XX:+UseConcMarkSweepGC

( CMS--> Card Marking JVM參數是-XX:UseCondCardMark 在高并發的情況下,Card标記為髒的操作本身就存在  着競争,使用這個參數可以避免卡片被重複标記為髒,進而提高性能)

 流程:

   (1) .初始标記:标記對象stw很短

   (2) .并發标記:app運作時運作,耗時長

   (3) .重新标記:多線程修複标記,stw比初始标記時間稍長

   (4) .并發清除:回收

總結,網際網路項目偏愛,配合ParNew效果很好,少卡頓

 6.G1 :将整個堆劃分為多個大小相等的獨立區域(Region) -XX:+UseG1GC

      新生代和老年代不再是實體隔離,它們都是一部分Region(不需要連續)的集合  

    -XX:MaxGCPauseMillis:為G1設定暫停時間目标,預設值為200毫秒;

      -XX:InitiatingHeapOccupancyPercent:當整個Java堆的占用率達到參數值時,

  開始并發标記階段;預設為45;

   -XX:G1HeapRegionSize:設定每個Region大小,範圍1MB到32MB;目标是在最小Java堆時可以擁有約2048個Region;

 特點:

  (1) .并行并發,充分利用CPU多核,和使用者程式同時進行,降低停頓時間

  (2) .分代收集:全部管理,将整個堆劃分為多個大小相等的獨立區域(Region)

  (3) .多算法結合:無碎片

  (4) .可預測停頓,低停頓同時實作高吞吐,可指定垃圾收集時間不超過N毫秒

 場景:

  (1) .超過50%的堆被活動資料占據

  (2) .對象配置設定頻率或年代更新頻率變化大

  (3) .停頓時間長于1S

 原理:

  (1) .将堆化為多個Region,

  (2) .跟蹤每個Region收集價值大小,維護一個優先清單

  (3) .根據允許的收集時間,優先回收價值最大的Region

  (4) .避免在堆的全區域垃圾收集

 流程:

  (1) .初始标記:标記對象stw很短

  (2) .并發标記:app運作時運作,耗時長

  (3) .最終标記:多線程修複标記,stw比初始标記時間稍長

  (4) .篩選回收:清單排序,複制壓縮整理,并發處理,降時間增吞吐

 總結,新型的收集器,目标是取代cms,核心是劃分區域分而治之。應用不廣

下面介紹一些GC相關參數

 -Xmx3550m:最大堆設為3550m

 -Xms2000m:初始堆設為2000m

 -Xmn2G:設定新生代2G

 -Xss128K:線程堆棧大小256K,可有更多線程,3-5K個

 -XX:MaxTenuringThreshold:新生代最大年齡,預設15

 -XX:NewRatio=4:新生代與老年代比值1/4,官方建議3/5,占整堆3/8

 -XX:SurvivorRatio=4:幸存區和伊甸區比例,倆個幸存區和伊甸區比例2/4,整新區2/6

 -XX:ParallelGCThreads=20:配置并行收集器的線程數

 -XX: MaxGCPauseMillis=100: 每次年輕代回收的最長時間,自調年輕代大小,以滿足此值

 -XX:+UseAdaptiveSizePolicy:并行收集器會自動選擇年輕代區大小和Survivor區比例

開始進入選擇優化階段

吞吐量優先  簡單的說就是處理快,允許卡頓,比如背景循環計算大量資料,客戶允許頁面異步接收資料慢一點

 Xmx3550m -Xms3550m -Xmn2g -Xss128k

 -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC

 配置新老垃圾收集方式為都并行收集

響應時間優先 簡單的說就是stw卡頓輕微不可查,網際網路項目為了客戶體驗是需要盡快傳回無明顯示卡頓

 -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

 配置新生代為并行收集,老年代為并發收集

 -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=5    -XX:+UseCMSCompactAtFullCollection

 -XX:CMSFullGCsBeforeCompaction:并發收集器不對記憶體空間進行壓縮整理,産生“碎片”, 使得運作效率降低。此值設  置運作多少次GC以後對記憶體空間進行壓縮整理。

 -XX:+UseCMSCompactAtFullCollection:壓縮老年代。可能影響性能,但是可以消除碎片

來自美團的GC經驗心得

 各分區的大小對GC的性能影響很大。如何将各分區調整到合适的大小,分析活躍資料的大小是很好的切入點。

 活躍資料的大小是指,應用程式穩定運作時長期存活對象在堆中占用的空間大小,也就是Full GC後堆中老年代占用 空間的大小。可以通過GC日志中Full GC之後老年代資料大小得出,比較準确的方法是在程式穩定後,多次擷取GC資料, 通過取平均值的方式計算活躍資料的大小。活躍資料和各分區之間的比例關系如下:

 根據GC日志獲得老年代的活躍資料大小為300MB,那麼各分區大小可以設為:

  總堆:1200MB = 300MB × 4

  新生代:450MB = 300MB × 1.5

  老年代: 750MB = 1200MB - 450MB*

這部分設定僅僅是堆大小的初始值,後面的優化中,可能會調整這些值,具體情況取決于應用程式的特性和需求。

總結:對大部分普通web項目,都不需要調整GC,隻需要減少大對象的持續引用,和循環建立class等,不會有太大問題。電商和網際網路項目要求就比較高了,

最後引用下imprtnow的測試各收集器處理GC時間的時間比較=------并行還是極快的

JVM之GC垃圾回收全面解析(二)