jvm系列(六):Java服務GC引數調優案例
本文介紹了一次生產環境的JVM GC相關引數的調優過程,通過引數的調整避免了GC卡頓對JAVA服務成功率的影響。
這段時間在整理jvm系列的文章,無意中發現本文,作者思路清晰通過步步分析最終解決問題。我個人特別喜歡這種實戰類的內容,經原作者的授權同意,將文章分享於此。原文連結:Java服務GC引數調優案例,下面為轉載此文的內容,備註部分為本人新增,主要起到說明的作用。
背景以及遇到的問題
我們的Java HTTP服務屬於OLTP型別,對成功率和響應時間的要求比較高,在生產環境中出現偶現的成功率突然下降然後又自動恢復的情況,如圖所示:
JVM和GC相關的引數如下:
-Xmx22528m
-Xms22528m
-XX:NewRatio=2
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
總結來說,由於服務中大量使用了Cache,所以堆大小開到了22G。GC演算法使用CMS(UseConcMarkSweepGC),開啟了降低標記停頓(CMSParallelRemarkEnabled),設定年輕代為並行收集(UseParNewGC),年輕代和老年代的比例為1:2 (NewRatio=2).
JVM GC日誌相關的引數如下:
-Xloggc:/data/gc.log
-XX:GCLogFileSize= 10M
-XX:NumberOfGCLogFiles=10
-XX:+UseGCLogFileRotation
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails
-XX:+DisableExplicitGC
-verbose:gc
問題解決過程
排除應用程式的記憶體使用問題
首先使用jmap檢視記憶體使用情況:
jmap -histo:live PID
這個命令把程式中當前的物件按照個數和佔用的空間排序以後打印出來。這裡沒有發現使用異常的物件。
排除Cache內容過多的問題
如果Cache內容過多也會導致JVM老年代容易被用滿導致頻繁GC,因此調出GC日誌進行檢視,發現每次GC以後記憶體使用一般是從20G降低到5G左右,因此常駐記憶體的Cache不是導致GC長時間卡頓的根本原因。對於GC LOG的檢視有多種方式,使用VisualVM比較直觀,需要使用VisualGC:
從圖中我們可以看到伊甸園和老年代的空間分配,由於整體記憶體是20G,設定 -XX:NewRatio=2 因此老年代是14G,伊甸園+S0+S1=7G
調整GC時間點(成功率抖動問題加重)
如果GC需要處理的記憶體量比較大,執行的時間也就比較長,STW (Stop the World)時間也就更長。按照這個思路調整CMS啟動的時間點,希望提早GC,也就是讓GC變得更加頻繁但是期望每次執行的時間較少。添加了下面這兩個引數:
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=50
意思是說在Old區使用了50%的時候觸發GC。實驗後發現GC的頻率有所增加,但是每次GC造成的陳功率降低現象並沒有減弱,因此棄用這兩個引數。
調整物件在年輕代記憶體中駐留的時間(效果不明顯)
如果能夠降低老年代GC的頻率也可以達到降低GC影響的目的,因此嘗試讓物件在年輕代記憶體中進行更長時間的駐留,提升這些物件在年輕代GC時候被銷燬的概率。使用引數-XX:MaxTenuringThreshold=31
調整以後收效不明顯。
備註:
1、MaxTenuringThreshold 在1.5.0_05之前最大值可以設定為31 ,1.5.0_06以後最大值可以設定為15,超過15會被認為無限大。參考:Never set GC parameter -XX:MaxTenuringThreshold greater than 15
2、提升年輕代GC被銷燬的概率,只是調整這個引數效果不大,第二次age的值會重新計算,參考:說說MaxTenuringThreshold這個引數
CMS-Remark之前強制進行年輕代的GC
首先補充一下CMS的相關知識,在CMS整個過程中有兩個步驟是STW的,如圖紅色部分:
CMS並非沒有暫停,而是用兩次短暫停來替代序列標記整理演算法的長暫停,它的收集週期是這樣:
- 1、初始標記(CMS-initial-mark),從root物件開始標記存活的物件
- 2、併發標記(CMS-concurrent-mark)
- 3、重新標記(CMS-remark),暫停所有應用程式執行緒,重新標記併發標記階段遺漏的物件(在併發標記階段結束後物件狀態的更新導致)
- 4、併發清除(CMS-concurrent-sweep)
- 5、併發重設狀態等待下次CMS的觸發(CMS-concurrent-reset)。
通過GC日誌和成功率下降的時間點進行比對發現並不是每一次老年代GC都會導致成功率的下降,但是從中發現了一個規律:
前兩次GC CMS-Remark過程在4s左右造成了成功率的下降,但是第三次GC並沒有對成功率造成明顯的影響,CMS-Remark只有0.18s。Java HTTP 服務是通過Nginx進行反向代理的,nginx設定的超時時間是3s,所以如果GC卡頓在3s以內就不會對成功率造成太大的影響。
從GC日誌中又發現一個資訊:
在文件和相關資料中沒有找到藍色部分的含義,猜測是remark處理的記憶體量,處理的越多就越慢。新增下面兩個引數強制在remark階段和FULL GC階段之前先在進行一次年輕代的GC,這樣需要進行處理的記憶體量就不會太多。
備註:
1、藍色部分的含義:remark標記需要清理物件的容量。關於如何分析CMS日誌,可以參考這篇文章:瞭解 CMS 垃圾回收日誌
2、FULL GC階段之前先在進行一次年輕代的GC的意義是:Yong區物件引用了Old區的物件,如果在Old區進行清理之前不進行Yong區清理,就會導致Old區被yong區引用的物件無法釋放。可以參考這篇文章:假笨說-又抓了一個導致頻繁GC的鬼–陣列動態擴容
-XX:+ScavengeBeforeFullGC
-XX:+CMSScavengeBeforeRemark
調優以後效果很明顯,下面是兩臺配置完全相同的伺服器在同一時間段的成功率和響應時間監控圖,第一個沒有新增強制年輕代GC的引數。
結論
1、在CMS-remark階段需要對堆中所有的記憶體物件進行處理,如果在這個階段之前強制執行一次年輕代的GC會大量減少remark需要處理的記憶體數量,進而降低JVM卡頓對成功率的影響。
2、對於Java HTTP服務,JVM的卡頓時間應該小於HTTP客戶端的呼叫超時時間,否則JVM卡頓會對成功率造成影響。
感謝匠心零度對文章內容進行深入的探討,備註內容屬於討論後的結果
參考文獻
相關推薦
jvm系列(六):Java服務GC引數調優案例
本文介紹了一次生產環境的JVM GC相關引數的調優過程,通過引數的調整避免了GC卡頓對JAVA服務成功率的影響。 這段時間在整理jvm系列的文章,無意中發現本文,作者思路清晰通過步步分析最終解決問題。我個人特別喜歡這種實戰類的內容,經原作者的授權同意,將文章分
JVM基礎系列教程|第五篇:Java服務GC引數調優案例
推薦視訊連結 本文介紹了一次生產環境的JVM GC相關引數的調優過程,通過引數的調整避免了GC卡頓對JAVA服務成功率的影響。 這段時間在整理jvm系列的文章,無意中發現本文,作者思路清晰通過步步分析最終解決問題。我個人特別喜歡這種實戰類的內容,經原作者的授權
JVM系列【6】GC與調優1
### JVM系列筆記目錄 > - 虛擬機器的基礎概念 > - class檔案結構 > - class檔案載入過程 > - jvm記憶體模型 > - JVM常用指令 > - GC與調優 ### GC基礎知識 - #### 什麼是垃圾 沒有任何引用指向的一個
JVM系列【6】GC與調優2.md
### JVM系列筆記目錄 > - 虛擬機器的基礎概念 > - class檔案結構 > - class檔案載入過程 > - jvm記憶體模型 > - JVM常用指令 > - GC與調優 #### 瞭解HotSpot常用命令列引數 JVM的命令列引數參考: http
JVM系列【6】GC與調優5-日誌分析
### JVM系列筆記目錄 > - 虛擬機器的基礎概念 > - class檔案結構 > - class檔案載入過程 > - jvm記憶體模型 > - JVM常用指令 > - GC與調優 #### 主要內容 分析PS、CMS、G1的回收日誌,目標使大概能讀懂GC日誌
JVM 垃圾回收機制與GC效能調優
一、GC概要: JVM堆相關知識 為什麼先說JVM堆? JVM的堆是Java物件的活動空間,程式中的類的物件從中分配空間,其儲存著正在執行著的應用程式用到的所有物件。這些物件的建立方式就是那些new一類的操作,當物件
高併發服務 系統引數調優相關
(*)系統引數 1、訊息佇列大小 和 可開啟檔案數 設定 /etc/sysctl.conf中增加以下配置 kernel.msgmni=1000 kernel.msgmax=81920 kernel.msgmnb=1638400 #fs.mqueue.msg_max=1000 #f
jvm系列(三):java GC算法 垃圾收集器
應對 sca 互聯 都是 生命 改進 壓縮 速度 垃圾收集器 原文鏈接:http://www.cnblogs.com/ityouknow/p/5614961.html 概述 垃圾收集 Garbage Collection 通常被稱為“GC”,它誕生於1960年 MIT 的
JAVA JVM引數調優、以及回收器
[轉]JVM系列三:JVM引數設定、分析 不管是YGC還是Full GC,GC過程中都會對導致程式執行中中斷,正確的選擇不同的GC策略,調整JVM、GC的引數,可以極大的減少由於GC工作,而導致的程式執行中斷方面的問題,進而適當的提高Java程式的工作效率。但是調整GC是以個極為複雜的過程,由於
Java架構學習(十二)java記憶體結構&新生代&老年代&JVM引數調優&堆記憶體引數配置&解決堆疊溢位
JVM引數調優與垃圾回收機制 一、java記憶體結構 Java記憶體模型:是多執行緒裡面的,jmm與執行緒可見性有關 Java記憶體結構:是JVM虛擬機器儲存空間。 Java記憶體結構圖 Java記憶體機構分為:方法區、java堆、棧、本地
jvm系列(九):Java GC 分析
Java GC就是JVM記錄儀,書畫了JVM各個分割槽的表演。 什麼是 Java GC Java GC(Garbage Collection,垃圾收集,垃圾回收)機制,是Java與C++/C的主要區別之一,作為Java開發者,一般不需要專門編寫記憶體回收和垃圾清理程式碼,對記憶體洩露和溢位的問題,也
jvm系列(三):java GC演算法 垃圾收集器
GC演算法 垃圾收集器 概述 垃圾收集 Garbage Collection 通常被稱為“GC”,它誕生於1960年 MIT 的 Lisp 語言,經過半個多世紀,目前已經十分成熟了。 jvm 中,程式計數器、虛擬機器棧、本地方法棧都是隨執行緒而生隨執行緒而滅,棧幀隨著方法的進入和退出做入棧和出棧
jvm系列(一):java類的加載機制
java語言 javac 字段 元素 對象實例 length 構造函數 class not 類加載機制的奧妙。 1、什麽是類的加載 類的加載指的是將類的.class文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然後在堆區創建一個java.lang.Clas
JVM字節碼與Java代碼層調優
構造 了解 arraycopy {} 修飾符 表達 stack 資源 cmd jvm字節碼指令 我們都知道,Java源代碼不會像C/C++那樣直接被編譯為機器碼,而是被編譯成字節碼,這造就了Java可以跨平臺的特性。JVM實際執行的也是編譯後的字節碼,所以想要在Java代碼
JVM系列(六) - JVM垃圾回收器
-c 公眾 進階 中一 比例 但是 member 最佳實踐 block 前言 在之前的幾篇博客中,我們大致介紹了,常見的 垃圾回收算法 及 JVM 中常見的分類回收算法。這些都是從算法和規範上分析 Java 中的垃圾回收,屬於方法論。在 JVM 中,垃圾回收的具體實現是由
HBase 核心元件協調及RegionServer JVM引數調優-OLAP商業環境實戰
本套技術專欄是作者(秦凱新)平時工作的總結和昇華,通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。版權宣告:禁止轉載,歡迎學習。QQ郵箱地址:[email protected],如有任何商業交流,可隨時聯絡。 1 弱化的Master
JVM(六):GC日誌閱讀
垃圾回收器的可用組合: Young Tenured JVM options Serial Serial -XX:+UseSerialGC Parallel Scavenge
機器學習系列(12)_XGBoost引數調優完全指南(附Python程式碼)
1. 簡介 如果你的預測模型表現得有些不盡如人意,那就用XGBoost吧。XGBoost演算法現在已經成為很多資料工程師的重要武器。它是一種十分精緻的演算法,可以處理各種不規則的資料。 構造一個使用XGBoost的模型十分簡單。但是,提高這個模型的表現就有些困難(至少我
jvm系列(一):java類的載入機制
1、什麼是類的載入 類的載入指的是將類的.class檔案中的二進位制資料讀入到記憶體中,將其放在執行時資料區的方法區內,然後在堆區建立一個java.lang.Class物件,用來封裝類在方法區內的資料結構。類的載入的最終產品是位於堆區中的Class物件,Clas
JAVA虛擬機器(六)調優案例分析與實戰
一個線上文件網站採用了新的硬體,4個CPU,16GB實體記憶體。管理員為了儘量利用硬體資源選用了64位的JDK1.5,並且將堆的大小固定位12GB。但是網站不定期出現失去響應的情況。 監控伺服器發現是由於GC停頓導致的,回收12GB的堆,一次Full GC停頓高