六、JVM調優(GC調優)

前言

JVM調優的本質:並不是爲了顯著的提升系統的性能,不是說調優過後,性能就能提升幾倍或者十幾倍,主要調的是穩定性。如果系統出現了頻繁的垃圾回收,這個系統是不穩定的,所以就需要我們來進行jvm調優,調整垃圾回收的頻次

一、GC調優原則

1、調優的原則

  • 大多數的 java 應用不需要 GC 調優
  • 大部分需要 GC 調優的的,不是參數問題,是代碼問題
  • 在實際使用中,分析 GC 情況優化代碼比優化 GC 參數要多得多;
  • GC 調優是最後的手段

2、調優的目的

GC 的時間夠小
GC 的次數夠少
發生 Full GC 的週期足夠的長,時間合理,最好是不發生

3、判斷是否需要調優的指標

Minor GC 執行時間不到 50ms;
Minor GC 執行不頻繁,約 10 秒一次;
Full GC 執行時間不到 1s;
Full GC 執行頻率不算頻繁,不低於 10 分鐘 1 次;

二、GC調優步驟

1、監控gc狀態

使用各種 JVM 工具,查看當前日誌,分析當前 JVM 參數設置,並且分析當前堆內存快照和 gc 日誌,根據實際的各區域內存劃分和 GC 執行時間,覺得是否進行優化

2、分析結果,判斷是否需要優化

如果各項參數設置合理,系統沒有超時日誌出現,GC 頻率不高,GC 耗時不高,那麼沒有必要進行 GC 優化;如果 GC 時間超過 1-3 秒,或者頻繁 GC,則 必須優化;

3、調整GC類型和內存分配

如果內存分配過大或過小,或者採用的 GC 收集器比較慢,則應該優先調整這些參數,並且先找 1 臺或幾臺機器進行 beta,然後比較優化過的機器和沒有 優化的機器的性能對比,並有針對性的做出最後選擇;

4、不斷的分析和調整

通過不斷的試驗和試錯,分析並找到最合適的參數

5、全面應用參數

如果找到了最合適的參數,則將這些參數應用到所有服務器,並進行後續跟蹤。

閱讀GC日誌

主要關注 MinorGC 和 FullGC 的回收效率(回收前大小和回收比較)、回收的時間。 -XX:+UseSerialGC

  • 以參數-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+UseSerialGC 爲例:
    [DefNew: 1855K->1855K(1856K), 0.0000148 secs][Tenured: 2815K->4095K(4096K), 0.0134819 secs] 4671K DefNew 指明瞭收集器類型,而且說明了收集發生在新生代。
    1855K->1855K(1856K)表示,回收前 新生代佔用 1855K,回收後佔用 1855K,新生代大小 1856K。 0.0000148 secs 表明新生代回收耗時。
    Tenured 表明收集發生在老年代
    2815K->4095K(4096K), 0.0134819 secs:含義同新生代
    最後的 4671K 指明堆的大小。
  • -XX:+UseParNewGC
    收集器參數變爲-XX:+UseParNewGC,日誌變爲:
    [ParNew: 1856K->1856K(1856K), 0.0000107 secs][Tenured: 2890K->4095K(4096K), 0.0121148 secs] 收集器參數變爲-XX:+ UseParallelGC 或 UseParallelOldGC,日誌變爲:
    [PSYoungGen: 1024K->1022K(1536K)] [ParOldGen: 3783K->3782K(4096K)] 4807K->4804K(5632K),

-XX:+UseConcMarkSweepGC
CMS 收集器和 G1 收集器會有明顯的相關字樣 -XX:+UseG1GC

三、GC實戰

1、項目啓動的優化

  • 開啓日誌分析 -XX:+PrintGCDetails 發現有多次 GC 包括 FullGC
  • 調整 Metadata 空間 -XX:MetaspaceSize=64m
  • 減少 Minor gc 次數,增加參數 -Xms500m
  • 減少 Minor gc 次數,調整參數 -Xms1000m
  • 增加新生代比重,增加參數 -Xmn900m GC 減少至 1 次
  • 加大新生代,調整參數 -Xms2000m -Xmn1800m 還是避免不了 GC,沒有必要調整這麼大,資源浪費

2、項目運行過程中優化

使用 jmeter 同時訪問項目接口進行壓測,使用 40 個線程,循環 2500 次進行壓力測試,觀察併發的變化。
jmeter 的聚合報告的參數解釋
在這裏插入圖片描述

2.1使用單線程 GC -XX:+UseSerialGC

在這裏插入圖片描述
吞吐量:11711.9/s
最長耗時請求:401ms

2.2使用多線程GC -XX:+UseParNewGC

在這裏插入圖片描述
吞吐量有一定上升,整體耗時少了一秒

2.3 使用 CMS -XX:+UseConcMarkSweepGC

在這裏插入圖片描述
CMS 採用了併發收集,所以 STW 的時間較小,吞吐量較單線程有一定提高,最大請求時間 MAX 有明顯的下降。

2.4使用 G1 -XX:+UseG1GC

在這裏插入圖片描述
G1 這裏的吞吐量是最大的,最大請求時間 MAX 有明顯的下降。

在請求中new 出一個1M大小的0bject,再進行壓測

在這裏插入圖片描述
吞吐量急劇下降,也驗證了我們JVM調優的原則
在這裏插入圖片描述

3、推薦策略

3.1新生代大小

  • 響應時間優先的應用:儘可能設大,直到接近系統的最低響應時間限制(根據實際情況選擇).在此種情況下,新生代收集發生的頻率也是最小 的.同時,減少到達老年代的對象.
  • 吞吐量優先的應用:儘可能的設置大,可能到達 Gbit 的程度.因爲對響應時間沒有要求,垃圾收集可以並行進行,一般適合 8CPU 以上的應用.
  • 避免設置過小.當新生代設置過小時會導致:1.MinorGC 次數更加頻繁 2.可能導致 MinorGC 對象直接進入老年代,如果此時老年代滿了,會觸發FullGC.

3.2老年代大小

  • 響應時間優先的應用:老年代使用併發收集器,所以其大小需要小心設置,一般要考慮併發會話率和會話持續時間等一些參數.如果堆設置小了,可 以會造成內存碎 片,高回收頻率以及應用暫停而使用傳統的標記清除方式; 如果堆大了,則需要較長的收集時間.最優化的方案,一般需要參考以下數據獲得:
    併發垃圾收集信息、持久代併發收集次數、傳統 GC 信息、花在新生代和老年代回收上的時間比例。
  • 吞吐量優先的應用:一般吞吐量優先的應用都有一個很大的新生代和一個較小的老年代.原因是,這樣可以儘可能回收掉大部分短期對象,減少中期的對象,而 老年代盡存放長期存活對象

jvm優化:逃逸分析

參數:
-XX:+DoEscapeAnalysis:啓用逃逸分析(默認打開) -XX:+EliminateAllocations:標量替換(默認打開)
-XX:+UseTLAB 本地線程分配緩衝(默認打開)

如果是逃逸分析出來的對象可以在棧上分配的話,那麼該對象的生命週期就跟隨線程了,就不需要垃圾回收,如果是頻繁的調用此方法則可以得到很大的性能提高(不用觸發GC)

採用了逃逸分析–對象在棧上分配:
在這裏插入圖片描述

沒有逃逸分析—對象都在堆上分配(觸發頻次 GC,加重負擔):
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章