記一次OOM查詢處理過程

記一次OOM查詢處理過程

 

  • 問題的爆出及分析排查現場

  • 排查後的解決方案

  • 項目的jvm參數

  • 總結

 

1、問題的爆出及分析排查現場

  服務偶爾會出現不可用的狀況,致使出現time out,而後我迅速登陸現場,直接查看當時的gc日誌,不廢話,直接上圖java

 

 

經過這個圖能夠發如今10點7分、8分的時候頻繁Full GC,可是GC以後 年輕代,老年代並無少。而且Full GC時長5s8多,形成stop-the-world5s8,所以應用程序會出現無影響。再貼一張圖web

 

經過這個能夠看到內存慢慢的經過GC降下來了併發

 根據這些信息基本能夠判定,是因爲什麼操做致使內存飆升,而且都是一些大對象,就是因爲這些大對象致使年輕代放不下,所以直接進入老年代(分配擔保策略),而這個操做佔用的內存大,所以觸發了Full GC(jvm 觸發Full GC的狀況 https://blog.csdn.net/chenleixing/article/details/46706039/ ),再加上又比較耗時,所以頻繁Full GC,由於對象一直被強引用着,致使沒法被清除.app

接下來立馬使用jdk 自帶的工具 jmap進行dump,而後使用jdk自帶的jvisualvm進行dump文件分析,分析圖以下:jvm

 

經過這個圖能夠看到Xobj相關的對象大小佔到內存的61%左右,因爲我對於這個項目又比較熟悉,因此很快就能定位是因爲操做Excel文件致使的.由於一看這個就知道是和xml解析相關的。函數

固然也能夠經過分析工具來定位到比較具體的點的信息(這個留給讀者來實操,復現現場,而後及時dump 堆內存進行分析,必定要在Xobj相關實例在可觸達的狀況下dump.找準時機)高併發

 

當定位是和Excel相關時,緊接着看了下和excel相關的處理文件,發現文件都不大,最大的也就40萬左右,7M而已,那麼爲何會產生這麼大的內存對象內,因而乎,就去百度,而後獲得的結果大概是poi讀取excel有兩種模式,一種user model 另外一種event mode, 而我使用的是user model 模式,這種模式使用的內存和cpu 較之 event model都要大不少。而我爲了方便,又是將excel 文件所有讀取而後進行處理。工具

 

2、排查後的解決方案

   解決方案分兩步走,一步是代碼層面、一步是jvm參數方面

    代碼層面:讀取excel文件使用event model 方式,而且每讀取100行,便處理而後釋放引用,這樣便於被GC回收

          jvm參數方面:以前年輕代是300M左右,而堆的總內存大小是4G,感受年輕代的設置不太合理,所以調到800M,而後進行觀察,觀察後可進行適當的調整

 

3、項目的jvm參數

-XX:CICompilerCount=3 	設置編譯線程的數量。JVM在server模式下默認是2,在client模式下默認是1。若是使用分層編譯的話,這個值會擴展到與CPU核數同樣的值。
-XX:InitialHeapSize=4294967296 	設置堆的初始值
-XX:InitialTenuringThreshold=5  設置初始的對象在新生代中最大存活次數
-XX:MaxHeapSize=4294967296 	設置堆分配的最大值,單位字節
-XX:MaxNewSize=348913664 	新生代佔整個堆內存的最大值。從Java1.4開始, MaxNewSize成爲 NewRatio的一個函數
-XX:MinHeapDeltaBytes=196608 

-XX:OldPLABSize=16 
-XX:OldSize=3946053632 

 
-XX:+UseCompressedOops  能夠壓縮指針,起到節約內存佔用的新參數。使用compressed pointers。這個參數默認在64bit的環境下默認啓動,可是若是JVM的內存達到32G後,這個參數就會默認爲不啓動,由於32G內存後,壓縮就沒有多大必要了,要管理那麼大的內存指針也須要很大的寬度了
-XX:SurvivorRatio=8  Eden與Survivor的佔用比例。例如8表示,一個survivor區佔用 1/8 的Eden內存,即1/10的新生代內存,爲何不是1/9? 由於咱們的新生代有2個survivor,即S1和S22。因此survivor總共是佔用新生代內存的 2/10,Eden與新生代的佔比則爲 8/10。
-XX:MaxMetaspaceSize=512M  這個參數用於限制Metaspace增加的上限,防止由於某些狀況致使Metaspace無限的使用本地內存,影響到其餘程序。在本機上該參數的默認值爲4294967295B(大約4096MB)
-XX:+UseCompressedClassPointers
-XX:CompressedClassSpaceSize=512M  的調優只有當-XX:+UseCompressedClassPointers開啓了纔有效
-XX:MaxTenuringThreshold=5	設置對象在新生代中最大的存活次數,最大值15,並行回收機制默認爲15,CMS默認爲4
 
-------------------CMS相關參數-------------------
-XX:CMSInitiatingOccupancyFraction=70  使用cms做爲垃圾回收使用70%後開始CMS收集

 
-------------------收集器設置-------------------
-XX:+UseConcMarkSweepGC   
	指 定在 Old Generation 使用 concurrent cmark sweep gc,gc thread 和 app thread 並行 ( 在 init-mark 和 remark 時 pause app thread). app pause 時間較短 , 適合交互性強的系統 , 如 web server 
-XX:+UseParNewGC 
	設置年輕代爲並行收集。可與CMS收集同時使用。JDK5.0以上,JVM會根據系統配置自行設置,因此無需再設置此值。
-------------------堆設置-------------------
-Xms4096m  
	指定 jvm 的最小 heap 大小 , 如 :-Xms=4g , 高併發應用, 建議和-Xmx同樣, 防止由於內存收縮/忽然增大帶來的性能影響。 
-Xmx4096m  
	指定 jvm 的最大 heap 大小
-XX:NewSize=348913664 
	設置年輕代大小
-XX:SurvivorRatio=8  
	指 定 New Generation 中 Eden Space 與一個 Survivor Space 的 heap size 比例 ,-XX:SurvivorRatio=8, 那麼在總共 New Generation 爲 10m 的狀況下 ,Eden Space 爲 8m 

-------------------垃圾回收統計信息-------------------
-XX:+PrintGC 
	輸出形式:[GC 118250K->113543K(130112K), 0.0094143 secs]
			  [Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDateStamps 
	GC發生的時間信息
-XX:+PrintGCDetails 
	輸出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
              [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps
	輸出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-Xloggc:logs/gc.log.201808142235  
	與上面幾個配合使用,把相關日誌信息記錄到文件以便分析

-------------------3個設置滾動記錄GC日誌的參數  測試一下    -------------------
-XX:+UseGCLogFileRotation 
	打開或關閉GC日誌滾動記錄功能,要求必須設置 -Xloggc參數
-XX:NumberOfGCLogFiles=1 
	設置滾動日誌文件的個數,必須大於1
	日誌文件命名策略是,<filename>.0, <filename>.1, ..., <filename>.n-1,其中n是該參數的值
-XX:GCLogFileSize=512M
	設置滾動日誌文件的大小,必須大於8k
	當前寫日誌文件大小超過該參數值時,日誌將寫入下一個文件
	

 

4、總結

  這個示例告訴咱們,使用任何第三方jar,都須要進行嚴格的測試,確保不會對現有的系統形成傷害。開發人員須要對jvm進行了解,特別是GC這塊,由於你new 的每一行代碼都是和GC相關的,至少密不可分,知道的越多,瞭解的越清楚,才能保證寫出好的 code ,有些坑不必定要踩性能

相關文章
相關標籤/搜索