記一次JVM調優之旅(鬥爭full gc)

俗話說技多不壓身,當年苦讀《深刻理解JVM》還專門整理了筆記,如今就用上了~html

筆記 http://www.cnblogs.com/syjkfind/p/3901774.htmljava

【症狀】 用戶操做數據導出時總會發生卡頓,後臺佔內存的定時任務發生時也會。JVM參數就不貼了,比較普通且相對合理。數據庫

【思路】緩存

查gc日誌是發生了full gc,tomcat日誌零零散散有不少exception。tomcat

另外憑着對代碼的瞭解,觸發時同時刻的日誌顯示正在執行較大數據量的查詢並且裝載進JVM,方法調用和臨時變量也不少。服務器

【分析】框架

1.minor gc很頻繁,但時間短因此問題不大,觸發緣由基本都是申請空間失敗。運維

2.偶爾有System.gc(),時間大概1分鐘。代碼中沒有顯式調用,基本肯定是監控程序RMI訪問觸發的。能夠加參數禁用 -XX:+DisableExplicitGC 。異步

3.時常有promotion failed,即在minor gc時年輕代的存活區空間不足而進入老年代,老年代又空間不足而觸發full gc。時間大概3分鐘。解決思路一種是增大存活區,一種則相反是去掉存活區增大老年代。相關參數通常有:大數據

-XX:SurvivorRatio=32 存活區除以伊甸區的比率,存活區有from和to兩個,因此這裏的意思是單個存活區佔年輕代的1/34;

-XX:OldSize=60M 老年代大小;

-XX:MaxTenuringThreshold=15 即多少次minor gc後存活的年輕代對象會晉升老年代。

4.常常有concurrent mode failure,即CMS執行過程當中老年代空間不足,這時會變成Serial Old收集器致使更長時間的停頓。時間大概5分鐘。其中引起這一問題的狀況多是浮動垃圾太多、多是CMS收集器自己也佔用堆空間、也多是老年代太多碎片,但都是CMS收集器的特性致使的。相關配置通常有:

-XX:CMSInitiatingOccupancyFraction=80 即老年代滿80%時觸發CMS(full gc),調高則full gc相對減小,調低則full gc處理得比較快;

-XX:UseCMSCompactAtFullCollection 或 -XX:CMSFullGCsBeforeCompaction=5 即full gc前或後作碎片整理。

5.另有個有趣的文章,過多過長的exception會致使promotion failed

http://www.th7.cn/Program/java/201511/685711.shtml

可能挺符合咱們的場景的,沒有運維權限,下次能夠考慮找運維dump個分析一下對象。

之前爲了追蹤錯誤關閉了「快拋」 -XX:-OmitStackTraceInFastThrow 即反覆出現的exception不會用一個靜態的沒堆棧信息的實例去代替,這個要權衡一下了。

【解決】

建立不少對象佔了年輕代?大對象致使佔滿老年代?浮動垃圾(CMS時繼續在產生臨時對象)或老年代碎片?

調優多少是能夠改善的,但彷佛代碼自己更有問題,恐怕分配再多的內存都不夠吃。好比沒有應用較完善的一級緩存二級緩存,好比常常粗暴地把上萬條記錄加載進來,還沒作分頁,還有藏的比較深的作了切面觸發異步服務把異步服務隊列佔滿了。初期享受了框架的便利而考慮設計的少,而如今則要開始還技術債務了~

所幸的是在有限的時間裏,咱們有簡單粗暴有效的方法緩解這些問題:加服務器,把大任務剝離出來~

而中長期的考慮來看,在不改變現有框架的前提下,整改exception、整改業務代碼作分頁、封裝數據庫分頁查詢框架、改造數據庫層二級緩存(集羣範圍內緩存)會是比較有效的措施。

更長遠的確定就是迴歸Spring系主流框架,再者進軍服務化了。。。但那個幾乎要把業務代碼從新寫一遍,是後話了。

迴歸主題若是是調優來解決問題,最好是dump了作更深刻的分析。主觀上看來啓用快拋、gc後碎片整理、增大存活區應該是比較有針對性的調整,而CMSInitiatingOccupancyFraction取值和CMS各階段細緻的配置則須要更量化的分析。

相關文章
相關標籤/搜索