1. 程式人生 > 實用技巧 >JVM常用調優方法

JVM常用調優方法

一、常用調優方法

1、將新物件預留在新生代

由於 Full GC 的成本要遠遠高於 Minor GC ,因此儘可能將物件分配在新生代,在JVM 調優中,可以為應用程式分配一個合理的新生代空間,以最大限度避免新物件直接進去老年代。

注意:由於新生代垃圾回收的速度高於老年代回收,因此,將年輕物件預留在新生代有利於提高整體的 GC 效率

2、大物件進入老年代

大物件佔用空間多,直接放入新生代中會擾亂新生代GC,新生代空間不足將會把大量的較小的年輕代物件移入到老年代中,這對GC來說是相當不利的。如果有短命大物件,對GC來說將會是一場災難,原本存放於老年代的永久物件,被短命大物件塞滿,擾亂了分代記憶體回收的基本思路,因此,在開發過程中,儘可能避免使用短命的大物件。使用引數 -XX

:PretenureSizeThreshold 設定大物件直接進入老年代的閥值,當物件超過這個閥值時,將直接在老年代中分配。其中, -XX:PretenureSizeThreshold 只對序列收集器和新生代並行收集器有效,並行回收收集器不識別這個引數

注意:短命的大物件對垃圾回收是一場災難,目前木有一種特別好的回收方法處理這個問題,因此儘可能避免使用短命的大物件。

3、設定物件進入老年代的年齡

在堆中每個物件都有自己的年齡,如果物件在 eden 區,經過一次 GC 後還存活,則被移動到 survivor 區中,物件年齡加 1,以後每經過一次 GC 依然存活的,物件年齡就加 1。當物件年齡達到閥值時,就移動到老年代,這個閥值用以下引數設定:

-XX:MaxTenuringThreshold:預設值是15,這個引數是指定進入老年代的最大年齡值,物件實際進入老年代的年齡是 JVM 在執行時根據記憶體使用情況動態計算的。

如果希望物件儘可能長地留在新生代中,可以設定一個較大的閥值。

4、穩定與震盪的堆大小

穩定的堆大小對垃圾回收是有利的,獲得一個穩定堆大小的方法就是設定 -Xmx 和 -Xms 一樣的值。不穩定的堆也不是木有用處,讓堆大小在一個區間內震盪,在系統不需要使用大記憶體時壓縮堆空間,使 GC 應對一個較小的堆,可以加快單次 GC 的速度。基於這種思想,JVM 提供了兩個引數用於壓縮和擴充套件堆空間,引數如下:

-XX:MinHeapFreeRatio

:設定堆空間最小空閒比例,預設是 40 ,當堆空間的空閒比例小於這個值時,JVM 便會擴充套件堆空間

-XX:MaxHeapFreeRatio:設定堆空間的最大空閒比例,預設是 70,當堆空間的空閒比例大於這個值時,JVM 便會壓縮堆空間,得到一個較小的堆

注意:當 -Xms 和 -Xmx 相等時,-XX:MinHeapFreeRatio 和 -XX:MaxHeapFreeRatio 這兩個引數無效

5、吞吐量優先設定

機器配置是 4G 記憶體 和 32 核 CPU,配置引數如下:

-Xms3800m -Xmx3800m(堆的初始值和最大值一樣)

-Xmn2g(新生代大小)

-Xss128k(執行緒棧大小,減少它使剩餘的系統記憶體支援更多的執行緒)

-XX:+UseParallelGC(新生代使用並行回收收集器)

-XX:ParallelGCThreads=20(垃圾回收的執行緒數)

-XX:+UseParallelOldGC (老年代使用並行回收收集器)

6、使用大頁案例

使用大的記憶體分頁可以增強 CPU 的記憶體定址能力,從而提高系統的效能,引數設定如下:

-XX:LargePageSizeInBytes:設定大頁的大小

7、降低停頓案例

為了降低應用軟體在垃圾回收時的停頓,首先考慮的使用關注系統停頓的 CMS 回收器,為了減少 Full GC 的次數,應儘可能將物件預留在新生代,新生代 Minor GC 的成本遠遠小於老年代的 Full GC

-Xms3800m -Xmx3800m(堆的初始值和最大值一樣)

-Xmn2g(新生代大小)

-Xss128k(執行緒棧大小,減少它使剩餘的系統記憶體支援更多的執行緒)

-XX:ParallelGCThreads=20(垃圾回收的執行緒數)

-XX:+UseConcMarkSweepGC(老年代使用 CMS 收集器)

-XX:+UseParNewGC(新生代使用並行收集器)

-XX:SurvivorRatio=8(設定 eden : survivor = 8 : 1)

-XX:TargetSurvivorRatio(設定 survivor 的使用率為 90%,預設是50%,提高了survivor 區的使用率,當存放的物件超過這個數值,則物件會向老年代壓縮)

-XX:MaxTenuringThreshold=31(設定年輕物件晉升到老年代的最大年齡是31,預設是15,設為31是儘可能地將物件留在新生代)

二、常用JVM引數

1、JIT編譯引數

JVM 的 JIT(Just-In-Time)編譯器,可以在執行時將位元組碼編譯成原生代碼,從而提高函式的執行效率。引數設定如下

-XX:CompileThreshold:JIT 編譯的閥值,當函式的呼叫超過這個值時,JIT 就將位元組碼編譯成本地機器碼。在 client 模式下,取值是 1500,在 server 模式下,取值是 10000

2、堆快照(堆 Dump)

在效能問題排查中,分析堆快照(Dump)是必不可少的一環。獲取程式的堆快照檔案有多種方法,下面介紹一種常用的方法,即使用 -XX:+HeapDumpOnOutOfMemoryError 引數在程式發生 OOM 時,匯出應用程式的當前堆快照。這是一種非常有效的方法,因為當程式發生 OOM 退出系統時,一些瞬時資訊都隨著程式的終止而消失,而重現 OOM 問題往往比較困難或者耗時,因此當發生 OOM 時,將堆資訊儲存到檔案中是至關重要的,通過下面的引數設定:

-XX:+HeapDumpOnOutOfMemoryError(開啟堆快照)

-XX:HeapDumpPath=C:/m.hprof(儲存檔案到哪個目錄)

匯出的 Dump 檔案可以通過 Visual VM 等多種工具檢視分析,進而定位問題,如下圖所示:

3、錯誤處理

系統發生 OOM 錯誤時,JVM 在錯誤發生時執行一段第三方指令碼,重置系統,設定引數如下:

-XX:OnOutOfMemoryError=C:\reset.bat

4、獲取 GC 資訊

獲取 GC 資訊是 java 應用程式調優最重要的一環,下面介紹一些常用的設定引數:

-XX:+PrintGC(-verbose:gc):輸出列印簡要的 GC 資訊,包括 GC 前的堆疊情況和 GC 後的堆疊大小和堆疊的總大小

-XX:+PrintGCDetails:輸出列印詳細的 GC 資訊,不僅包括基本資訊,還給出了新生代、老年代和永久區各自的 GC 資訊

-XX:+PrintGCTimeStamps:額外輸出 GC 發生的時間,可以推斷出 GC 的頻率和間隔

-XX:+PrintTenuringDistribution -XX:MaxTenuringThreshold=18:檢視新生代晉升老年代的實際閥值(-XX:+PrintTenuringDistribution),設定的最大年齡為18( -XX:MaxTenuringThreshold=18

-XX:+PrintHeapAtGC:每次 GC 時都會列印堆的詳細使用情況,輸出量很巨大。它分為兩個部分:GC 前的堆資訊和 GC 後的堆資訊,這裡包含了新生代、老年代和永久區的使用大小和使用率,還包括了新生代中 eden 區和 survivor 區的使用情況

-XX:+PrintGCApplicationStoppedTime:應用程式在 GC 發生時的停頓時間

-XX:+PrintGCApplicationConcurrentTime:應用程式在 GC 停頓期間的執行時間

-Xloggc:C:/gc.log:將 GC 日誌資訊輸出到具體位置的檔案中,便於日後日誌分析

注意:詳細的 GC 資訊是進行 JVM 調優的重要參考資訊,可以根據 GC 日誌,設定合理的堆大小及相關垃圾回收器的引數

5、類和物件跟蹤

JVM 提供了一組引數,用於獲取系統執行時載入、解除安裝類的資訊,引數設定如下:

-XX:TraceClassLoading:跟蹤類載入情況

-XX:TraceClassUnloading:跟蹤類的解除安裝情況

-verbose:class:相當於同時設定 -XX:TraceClassLoading 和 -XX:TraceClassUnloading 兩個引數

-XX:+PrintClassHistogram:列印執行時例項的資訊,當設定此引數後,使用 Ctrl + Break 會輸出系統內類的統計資訊,從左到右依次顯示了序號、例項數量、總大小和類名等資訊

6、控制GC

-XX:DisableExplicitGC:禁止 GC 操作,即禁止在程式中使用 System.gc() 觸發 Full GC

-Xnoclassgc:禁止類的回收

-Xingc增量式的 GC ,增量式的 GC 使用特定的演算法讓 GC 執行緒和應用程式執行緒交叉執行,從而減少應用程式因 GC 產生的停頓時間

-Xverify:none:關閉類校驗器

-XX:+UseLargePages:啟用大頁,使用大頁後,記憶體分頁的表項就會減少,從而提升CPU從虛擬記憶體地址對映到實體記憶體地址的能力

-XX:LargePageSizeInBytes:指定大頁的大小