java架構之路-(JVM優化與原理)JVM之G1回收器和常見參數配置

  過去的幾天裏,我把JVM內部的垃圾回收算法和垃圾回收器。還剩下最後一個G1回收器沒有說,咱們今天數一下G1回收器和常見的參數配置。java

G1回收器算法

G1 (Garbage-First)是一款面向服務器的垃圾收集器,主要針對配備多顆處理器及大容量內存的機器,以極高機率知足GC停頓時間要求的同時,還具有高吞吐量性能特徵。咱們會想一下咱們上次課說的parNew+CMS回收器已經很厲害了,可是咱們的服務器是那種超大內存的服務器呢?好比內存是32G的,可能最後咱們的堆內存須要分配到十多個G,咱們用parNew+CMS對於STW時間仍是很長的,須要清理的越多,時間消耗越長啊,可是咱們的G1垃圾回收器能夠作到限制時間來收集,咱們先看一下G1的模型圖。

來解釋一下這個圖,G1垃圾回收器,會把你的堆內存分爲大小相等的獨立區域(Region),JVM最多能夠分配2048個Region,通常Region大小等於堆大小除以2048,好比堆大小爲4096M,則Region大小爲2M,固然也能夠 用參數"-XX:G1HeapRegionSize"手動指定Region大小,每一個Region的狀態不肯定,多是Eden區域,也多是Old區域,不須要原有的聯繫設置,這裏說一下之前沒有提到的Humongous區域,他是用來存儲大對象的,大對象的斷定規則就是一個大對象超過了一個Region大小的50%,好比按 照上面算的,每一個Region是2M,只要一個大對象超過了1M,就會被放入Humongous中視對象大小而定格子的連續數目。服務器

默認年輕代對堆內存的佔比是5%,若是堆大小爲4096M,那麼年輕代佔據200MB左右的內存, 對應大概是100個Region,能夠經過「-XX:G1NewSizePercent」設置新生代初始佔比,在系統 運行中,JVM會不停的給年輕代增長更多的Region,可是最多新生代的佔比不會超過60%,能夠 經過「-XX:G1MaxNewSizePercent」調整。年輕代中的Eden和Survivor對應的region也跟以前 同樣,默認8:1:1,假設年輕代如今有1000個region,eden區對應800個,s0對應100個,s1對應 100個。併發

G1收集器一次GC的運做過程大體分爲如下幾個步驟:
初始標記(initial mark,STW):暫停全部的其餘線程,並記錄下gc roots直接能引用的對象,速度很快 ;
併發標記(Concurrent Marking):同CMS的併發標記
最終標記(Remark,STW):同CMS的從新標記
篩選回收(Cleanup,STW):篩選回收階段首先對各個Region的回收價值和成本進行排序,根據用戶所指望的GC停頓時間(能夠用JVM參數 -XX:MaxGCPauseMillis指定)來制定回收計劃,就是說咱們但願每次STW時間只是100ms,咱們能夠指定垃圾回收完成時間爲100ms,可是100ms是不必定徹底回收完成的,咱們會按照每個格子的回收消耗時間來排序,由小到大進行回收處理,直到時間爲100ms爲止。
這裏的回收算法是複製算法,也就是咱們把每個小格子的對象進行處理,把有用的對象複製到空格子內,把原有格子清空,須要注意一點的是不須要再次整理內存碎片,舉一個實例,Region1和Region2都須要回收,他們的大小都爲2M,Region1有0.3M的對象是有用的,Region2的對象有0.6是有用,這時他們會共同放在一個空的小格子內佔用0.9M的大小。
與咱們之前熟悉的YoungGC和OldGC所不一樣的是G1的回收器有三種GC,分別爲:
YoungGC:
YoungGC並非說現有的Eden區放滿了就會立刻觸發,G1會計算下如今Eden區回收大概要多久時間,若是回收時間遠遠小於參數 -XX:MaxGCPauseMills 設定的值,那麼增長年輕代的region,繼續給新對象存放,不會立刻作YoungGC,直到下一次Eden區放滿,G1計算回收時間接近參數 -XX:MaxGCPauseMills 設定的值,那麼就會觸發YoungGC

MixedGC:jvm

不是FullGC,老年代的堆佔有率達到參數(-XX:InitiatingHeapOccupancyPercen)設定的值則觸發,回收全部的Young和部分Old(根據指望的GC停頓時間肯定old區垃圾收集的優先順序)以及大對象區,正常狀況G1的垃圾收集是先作MixedGC,主要使用複製算法,須要把各個region中 存活的對象拷貝到別的region裏去,拷貝過程當中若是發現沒有足夠的空region可以承載拷貝對象 就會觸發一次Full GC性能

Full GC:優化

中止系統程序,而後採用單線程進行標記、清理和壓縮整理,好空閒出來一批Region來供下一次MixedGC使用,這個過程是很是耗時的。spa

JVM參數配置以及優化(JDK1.8)線程

棧相關調試

-Xss->設置單個線程棧大小,好比-Xss512K,數值越小,一個線程棧裏能分配的棧幀就越少,說明能夠開啓的線程數越多

方法區(元空間)

-XX:MetaspaceSize->設置方法區的大小,也是觸發GC的閾值,好比-XX:MetaspaceSize=256M

-XX:MaxMetaspaceSiz->設置方法區的最大值,好比-XX:MaxMetaspaceSize=256M 

堆相關

-Xms->jvm啓動時分配的內存,好比‐Xms200m

-Xmx->jvm運行過程當中分配的最大內存,好比-Xmx500m

-Xmn->設置年輕代大小,好比-Xmn2g

-XX:NewSize->設置年輕代大小 好比-XX:NewSize=2g

-XX:PretenureSizeThreshold->能夠設置大對象的大小,好比-XX:PretenureSizeThreshold=100000000 單位爲btye。

-XX:MaxTenuringThreshold ->設置分代年齡,好比-XX:MaxTenuringThreshold=10 默認爲15。

-XX:-HandlePromotionFailure->老年代分配擔保機制參數,1.8默認開啓。

-XX:-UseAdaptiveSizePolicy->禁止JVM自動優化eden和Survivor默認比例8:1:1,反之JVM默認有這個參數-XX:+UseAdaptiveSizePolicy,會致使這個比例自動變化。

-XX:SurvivorRatio->設置Eden和Survivor大小好比 -XX:SurvivorRatio =8,注意Survivor區有兩個。表示Eden:Survivor=8:2,一個Survivor區佔整個年輕代的1/10。

-XX:NewRatio->設置老年代和年輕代的比值大小 好比-XX:NewRatio=4,表示年老代和年輕代比值爲4:1。

回收器相關

Serial收集器

-XX:+UseSerialGC->指定年輕代爲Serial收集器

-XX:+UseSerialOldGC->指定老年代爲Serial收集器

ParNew收集器

-XX:+UseParNewG->指定年輕代爲ParNew收集器

Parallel Scavenge收集器

-XX:+UseParallelGC->指定年輕代爲Parallel收集器

-XX:+UseParallelOldGC->指定老年代爲Parallel收集器

-XX:ParallelGCThreads->指定GC工做的線程數量

CMS收集器

-XX:+UseConcMarkSweepGC->指定指定老年代爲CMS收集器

-XX:ConcGCThreads->併發的GC線程數

-XX:+UseCMSCompactAtFullCollection->FullGC以後是否作壓縮整理(減小碎片)

-XX:CMSFullGCsBeforeCompaction->多少次FullGC以後壓縮一次,默認是0,表明每次FullGC後都會壓縮一次,好比-XX:CMSFullGCsBeforeCompaction=0 

-XX:CMSInitiatingOccupancyFraction->當老年代使用達到該比例時會觸發FullGC(默認是92,這是百分比),好比-XX:CMSInitiatingOccupancyFaction=92

-XX:+UseCMSInitiatingOccupancyOnly->只使用設定的回收閾值(-XX:CMSInitiatingOccupancyFraction設定的值),若是不指定,JVM僅在第一次使用設定值,後續則會自動調整

-XX:+CMSScavengeBeforeRemark->在CMSGC前啓動一次minor gc,目的在於減小老年代對年輕代的引用,下降CMS GC的標記階段時的開銷,通常CMS的GC耗時80%都在 remark階段 

G1收集器

-XX:+UseG1GC->開啓G1收集器

-XX:G1HeapRegionSize->指定分區大小(1MB~32MB,且必須是2的冪),默認將整堆劃分爲2048個分區

-XX:MaxGCPauseMillis->目標暫停時間(默認200ms)

-XX:G1NewSizePercent->新生代內存初始空間(默認整堆5%)

-XX:G1MaxNewSizePercent->新生代內存最大空間

-XX:TargetSurvivorRatio->Survivor區的填充容量(默認50%),Survivor區域裏的一批對象(年齡1+年齡2+年齡n的多個年齡對象)總和超過了Survivor區域的50%,此時就會把年齡n(含)以上的對象都放入老年代

-XX:InitiatingHeapOccupancyPercent->老年代佔用空間達到整堆內存閾值(默認45%),則執行 新生代和老年代的混合收集(MixedGC),好比咱們以前說的堆默認有2048個region,若是有接近 1000個region都是老年代的region,則可能就要觸發MixedGC了

-XX:G1HeapWastePercent->默認5%,gc過程當中空出來的region是否充足閾值,在混合回收的時候,對Region回收都是基於複製算法進行的,都是把要回收的Region裏的存活對象放入其餘 Region,而後這個Region中的垃圾對象所有清理掉,這樣的話在回收過程就會不斷空出來新的 Region,一旦空閒出來的Region數量達到了堆內存的5%,此時就會當即中止混合回收,意味着 本次混合回收就結束了。

-XX:G1MixedGCLiveThresholdPercent->默認85%,region中的存活對象低於這個值時纔會回收該region,若是超過這個值,存活對象過多,回收的的意義不大。

-XX:G1MixedGCCountTarget->在一次回收過程當中指定作幾回篩選回收(默認8次),在最後一個篩選回收階段能夠回收一會,而後暫停回收,恢復系統運行,一會再開始回收,這樣可讓系統不至於單次停頓時間過長。 

日誌調優相關

-XX:+PrintGCDetails->打印GC日誌

-XX:+PrintGCTimeStamps->打印GC時間

-XX:+PrintGCDateStamps->打印GC日期

-Xloggc->將GC日誌保存爲文件,好比-Xloggc:./gc.log

有興趣的小夥伴能夠自學一下jmap -heap PID,jstat -gc PID(我的認爲這個超級重要),javap -c ***.class,Jstack等調優命令,線上盡力別用jvisualvm命令,消耗性能,不少公司禁用jvisualvm命令

咱們來回顧一下咱們JVM都說了什麼知識點。

一,類加載過程:加載-驗證-準備-解析-初始化-使用-卸載

二,雙親委派機制。

三,內存運行模型(堆和棧)

四,內存分區老年代和年輕代,年輕代包含Eden區和Survivor區。

五,GC回收minor和fullGC,何時會觸發fullGC,重點是對象動態年齡判斷和老年代擔保分配機制。

六,垃圾回收的算法,三種,複製,標記清理,標記整理。

七,垃圾回收器五種,串行的Serial,並行的parNew,高CPU的Parallel,經常使用的CMS和大內存的G1。

八,經常使用命令。

不少都是孰能生巧的,細節的還有不少,JVM優化路我給大家指出了,剩下的還須要大家本身去探索,加油~!!!

再不會調優的能夠來私信我,我能夠嘗試爲你提出免費調試建議。

 

最進弄了一個公衆號,小菜技術,歡迎你們的加入

相關文章
相關標籤/搜索