CMS垃圾收集器總結


一 公司CMS參數

先說一下公司CMS參數,年輕代3.5G, 其中survivor 50M。老年代1.5G,其實用不到500M,原空間250M。

二 常見參數配置

  1 開啟 CMS

  首先,要說的是,CMS只是老年代的垃圾收集器。其年輕代使用的是ParNew垃圾收集器。

  其次,JDK8默認的垃圾收集器並不是CMS,需要手動指定。-XX:+UseConcMarkSweepGC -XX:+UseParNewGC 

  2 設置堆大小

  使用CMS建議總堆空間不超過8G,最好是6G以內。因為如果發生FGC,太大的堆空間會讓FGC的STW時間變的特別的長。

  -Xmx4G -Xms4G -Xmn1512M

  3 線程棧

  JDK8默認的線程棧大小是1M,絕大多數微服務項目可以調整為512K -XSS512K

  4 -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly

   表示只有在老年代達到了70%才進行回收

  5 -XX:MetaspaceSize=314572800  其實是300M

     因為之前發生過元空間引發的FGC,所以我們項目把這個參數調大了。因為本項目的特點是,會請求大量的接口,引入大量的類。

  6 dump路徑

   必須配置,因為如果發生了OOM,不dump的話,沒法定位問題。

     -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/applogs/system/error.dump

  7 GC 日志

   必須配置

      -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 

   -Xloggc:/data/log/gclog/gc.log

  8 壓縮

  CMS是一種並發標記清除算法,而不是標記整理算法。所以,它不會進行碎片內存的移動和整理。

  -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0

  0表示每次發生fullgc 都進行壓縮整理

  9 卸載類

  -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses

  如果項目中使用了Netty,或者代碼里用了堆外內存,只有FGC才能回收這樣的堆外內存。也就是說想手動清理堆外內存就得執行System.gc()。而System.gc()觸發的是serial old垃圾收集器,時間會很長,一般在5s左右。而FGC的STW的時間會很長,(CMS的完整FGC是退化為線性GC)。而CMS GC暫停服務的時間較短。因此,加了這個參數可以有效地回收堆外內存並且減少暫停時間。

  這兩個參數也是用來改變System.gc()的默認行為用的;不同的 是這兩個參數只能配合CMS使用(-XX:+UseConcMarkSweepGC),而且System.gc()還是會觸發GC的,只不過不是觸發一個 完全stop-the-world的full GC,而是一次並發GC周期。也還是會觸發對外內存的回收。

  

  • CMS采用了Mark-Sweep算法,最后會產生許多內存碎片,當到一定數量時,CMS無法清理這些碎片了,CMS會讓Serial Old垃圾處理器來清理這些垃圾碎片,而Serial Old垃圾處理器是單線程操作進行清理垃圾的,效率很低。所以使用CMS就會出現一種情況,硬件升級了,卻越來越卡頓,其原因就是因為進行Serial Old GC時,效率過低。
  • 解決方案:使用Mark-Sweep-Compact算法,減少垃圾碎片
  • 調優參數(配套使用):-XX:+UseCMSCompactAtFullCollection 開啟CMS的壓縮
    -XX:CMSFullGCsBeforeCompaction 默認為0,指經過多少次CMS FullGC才進行壓縮
  • 當JVM認為內存不夠,再使用CMS進行並發清理內存可能會發生OOM的問題,而不得不進行Serial Old GC,Serial Old是單線程垃圾回收,效率低
  • 解決方案:降低觸發CMS GC的閾值,讓浮動垃圾不那么容易占滿老年代
  • 調優參數:-XX:CMSInitiatingOccupancyFraction 92% 可以降低這個值,讓老年代占用率達到該值就進行CMS GC

  

附上公司啟動腳本

  

java -jar -javaagent:/data/gravity/gravity-agent.jar=appName=trade-om-app,baseUrl=http://gravity-api.amh-group.com,appType=jar 
-Xms8192m -Xmx8192m -Xmn5460m -XX:MetaspaceSize=300m -XX:MaxMetaspaceSize=600m -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/applogs/system/error.dump -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
-XX:CMSInitiatingOccupancyFraction=70 -XX:+PrintGCDateStamps -XX:+UseCMSInitiatingOccupancyOnly -XX:+UnlockDiagnosticVMOptions
-XX:+UnsyncloadClass -XX:+UseParNewGC -XX:+PrintGCDetails -Xloggc:/data/applogs/system/gc_202007061528.log

  可以看到 配置eden和survivor比例沒有配置,應該是使用默認的。

  

  IBM論文里說據他們統計95%的對象朝生夕死一樣存活時間極短,為了保險默認實際使用了90%:設置eden 和survivor(兩個)為4:1,每次GC都將Eden和其中一個survivor(from)中的存活對象復制到剩余的survivor(to)中


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM