過去的幾天里,我把JVM內部的垃圾回收算法和垃圾回收器。還剩下最后一個G1回收器沒有說,我們今天數一下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個。
初始標記(initial mark,STW):暫停所有的其他線程,並記錄下gc roots直接能引用的對象,速度很快 ;

與我們以前熟悉的YoungGC和OldGC所不同的是G1的回收器有三種GC,分別為:
MixedGC:
不是FullGC,老年代的堆占有率達到參數(-XX:InitiatingHeapOccupancyPercen)設定的值則觸發,回收所有的Young和部分Old(根據期望的GC停頓時間確定old區垃圾收集的優先順序)以及大對象區,正常情況G1的垃圾收集是先做MixedGC,主要使用復制算法,需要把各個region中 存活的對象拷貝到別的region里去,拷貝過程中如果發現沒有足夠的空region能夠承載拷貝對象 就會觸發一次Full GC
Full GC:
停止系統程序,然后采用單線程進行標記、清理和壓縮整理,好空閑出來一批Region來供下一次MixedGC使用,這個過程是非常耗時的。
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:-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優化路我給你們指出了,剩下的還需要你們自己去探索,加油~!!!
再不會調優的可以來私信我,我可以嘗試為你提出免費調試建議。
最進弄了一個公眾號,小菜技術,歡迎大家的加入