1. 程式人生 > >JVM效能調優詳解

JVM效能調優詳解

前面我們學習了整個JVM系列,最終目標的不僅僅是瞭解JVM的基礎知識,也是為了進行JVM效能調優做準備。這篇文章帶領大家學習JVM效能調優的知識。

效能調優

效能調優包含多個層次,比如:架構調優、程式碼調優、JVM調優、資料庫調優、作業系統調優等。

架構調優和程式碼調優是JVM調優的基礎,其中架構調優是對系統影響最大的。

效能調優基本上按照以下步驟進行:明確優化目標、發現效能瓶頸、效能調優、通過監控及資料統計工具獲得資料、確認是否達到目標。

何時進行JVM調優

遇到以下情況,就需要考慮進行JVM調優了:

  • Heap記憶體(老年代)持續上漲達到設定的最大記憶體值;
  • Full GC 次數頻繁;
  • GC 停頓時間過長(超過1秒);
  • 應用出現OutOfMemory 等記憶體異常;
  • 應用中有使用本地快取且佔用大量記憶體空間;
  • 系統吞吐量與響應效能不高或下降。

JVM調優的基本原則

JVM調優是一個手段,但並不一定所有問題都可以通過JVM進行調優解決,因此,在進行JVM調優時,我們要遵循一些原則:

  • 大多數的Java應用不需要進行JVM優化;
  • 大多數導致GC問題的原因是程式碼層面的問題導致的(程式碼層面);
  • 上線之前,應先考慮將機器的JVM引數設定到最優;
  • 減少建立物件的數量(程式碼層面);
  • 減少使用全域性變數和大物件(程式碼層面);
  • 優先架構調優和程式碼調優,JVM優化是不得已的手段(程式碼、架構層面);
  • 分析GC情況優化程式碼比優化JVM引數更好(程式碼層面);

通過以上原則,我們發現,其實最有效的優化手段是架構和程式碼層面的優化,而JVM優化則是最後不得已的手段,也可以說是對伺服器配置的最後一次“壓榨”。

JVM調優目標

調優的最終目的都是為了令應用程式使用最小的硬體消耗來承載更大的吞吐。jvm調優主要是針對垃圾收集器的收集效能優化,令執行在虛擬機器上的應用能夠使用更少的記憶體以及延遲獲取更大的吞吐量。

  • 延遲:GC低停頓和GC低頻率;
  • 低記憶體佔用;
  • 高吞吐量;

其中,任何一個屬性效能的提高,幾乎都是以犧牲其他屬性效能的損為代價的,不可兼得。具體根據在業務中的重要性確定。

JVM調優量化目標

下面展示了一些JVM調優的量化目標參考例項:

  • Heap 記憶體使用率 <= 70%;
  • Old generation記憶體使用率<= 70%;
  • avgpause <= 1秒;
  • Full gc 次數0 或 avg pause interval >= 24小時 ;

注意:不同應用的JVM調優量化目標是不一樣的。

JVM調優的步驟

一般情況下,JVM調優可通過以下步驟進行:

  • 分析GC日誌及dump檔案,判斷是否需要優化,確定瓶頸問題點;
  • 確定JVM調優量化目標;
  • 確定JVM調優引數(根據歷史JVM引數來調整);
  • 依次調優記憶體、延遲、吞吐量等指標;
  • 對比觀察調優前後的差異;
  • 不斷的分析和調整,直到找到合適的JVM引數配置;
  • 找到最合適的引數,將這些引數應用到所有伺服器,並進行後續跟蹤。

以上操作步驟中,某些步驟是需要多次不斷迭代完成的。一般是從滿足程式的記憶體使用需求開始的,之後是時間延遲的要求,最後才是吞吐量的要求,要基於這個步驟來不斷優化,每一個步驟都是進行下一步的基礎,不可逆行之。

JVM引數

JVM調優最重要的工具就是JVM引數了。先來了解一下JVM引數相關內容。

-XX 引數被稱為不穩定引數,此類引數的設定很容易引起JVM 效能上的差異,使JVM存在極大的不穩定性。如果此類引數設定合理將大大提高JVM的效能及穩定性。

不穩定引數語法規則包含以下內容。

布林型別引數值:

  • -XX:+
  • -XX:-

數字型別引數值:

  • -XX:

字串型別引數值:

  • -XX:

JVM引數解析及調優

比如以下引數示例:

-Xmx4g –Xms4g –Xmn1200m –Xss512k -XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:PermSize=100m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15

上面為Java7及以前版本的示例,在Java8中永久代的引數-XX:PermSize和-XX:MaxPermSize已經失效。這在前面章節中已經講到。

引數解析:

  • -Xmx4g:堆記憶體最大值為4GB。
  • -Xms4g:初始化堆記憶體大小為4GB。
  • -Xmn1200m:設定年輕代大小為1200MB。增大年輕代後,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。
  • -Xss512k:設定每個執行緒的堆疊大小。JDK5.0以後每個執行緒堆疊大小為1MB,以前每個執行緒堆疊大小為256K。應根據應用執行緒所需記憶體大小進行調整。在相同實體記憶體下,減小這個值能生成更多的執行緒。但是作業系統對一個程序內的執行緒數還是有限制的,不能無限生成,經驗值在3000~5000左右。
  • -XX:NewRatio=4:設定年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設定為4,則年輕代與年老代所佔比值為1:4,年輕代佔整個堆疊的1/5
  • -XX:SurvivorRatio=8:設定年輕代中Eden區與Survivor區的大小比值。設定為8,則兩個Survivor區與一個Eden區的比值為2:8,一個Survivor區佔整個年輕代的1/10
  • -XX:PermSize=100m:初始化永久代大小為100MB。
  • -XX:MaxPermSize=256m:設定持久代大小為256MB。
  • -XX:MaxTenuringThreshold=15:設定垃圾最大年齡。如果設定為0的話,則年輕代物件不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設定為一個較大值,則年輕代物件會在Survivor區進行多次複製,這樣可以增加物件再年輕代的存活時間,增加在年輕代即被回收的概論。

新生代、老生代、永久代的引數,如果不進行指定,虛擬機器會自動選擇合適的值,同時也會基於系統的開銷自動調整。

可調優引數:

-Xms:初始化堆記憶體大小,預設為實體記憶體的1/64(小於1GB)。

-Xmx:堆記憶體最大值。預設(MaxHeapFreeRatio引數可以調整)空餘堆記憶體大於70%時,JVM會減少堆直到-Xms的最小限制。

-Xmn:新生代大小,包括Eden區與2個Survivor區。

-XX:SurvivorRatio=1:Eden區與一個Survivor區比值為1:1。

-XX:MaxDirectMemorySize=1G:直接記憶體。報java.lang.OutOfMemoryError: Direct buffer memory異常可以上調這個值。

-XX:+DisableExplicitGC:禁止執行期顯式地呼叫System.gc()來觸發fulll GC。

注意: Java RMI的定時GC觸發機制可通過配置-Dsun.rmi.dgc.server.gcInterval=86400來控制觸發的時間。

-XX:CMSInitiatingOccupancyFraction=60:老年代記憶體回收閾值,預設值為68。

-XX:ConcGCThreads=4:CMS垃圾回收器並行執行緒線,推薦值為CPU核心數。

-XX:ParallelGCThreads=8:新生代並行收集器的執行緒數。

-XX:MaxTenuringThreshold=10:設定垃圾最大年齡。如果設定為0的話,則年輕代物件不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設定為一個較大值,則年輕代物件會在Survivor區進行多次複製,這樣可以增加物件再年輕代的存活時間,增加在年輕代即被回收的概論。

-XX:CMSFullGCsBeforeCompaction=4:指定進行多少次fullGC之後,進行tenured區 記憶體空間壓縮。

-XX:CMSMaxAbortablePrecleanTime=500:當abortable-preclean預清理階段執行達到這個時間時就會結束。

在設定的時候,如果關注效能開銷的話,應儘量把永久代的初始值與最大值設定為同一值,因為永久代的大小調整需要進行FullGC才能實現。

記憶體優化示例

當JVM執行穩定之後,觸發了FullGC我們一般會拿到如下資訊:

以上gc日誌中,在發生fullGC之時,整個應用的堆佔用以及GC時間。為了更加精確需多次收集,計算平均值。或者是採用耗時最長的一次FullGC來進行估算。上圖中,老年代空間佔用在93168kb(約93MB),以此定為老年代空間的活躍資料。則其他堆空間的分配,基於以下規則來進行。

  • java heap:引數-Xms和-Xmx,建議擴大至3-4倍FullGC後的老年代空間佔用。
  • 永久代:-XX:PermSize和-XX:MaxPermSize,建議擴大至1.2-1.5倍FullGc後的永久帶空間佔用。
  • 新生代:-Xmn,建議擴大至1-1.5倍FullGC之後的老年代空間佔用。
  • 老年代:2-3倍FullGC後的老年代空間佔用。

基於以上規則,則對引數定義如下:

java -Xms373m -Xmx373m -Xmn140m -XX:PermSize=5m -XX:MaxPermSize=5m

延遲優化示例

對延遲性優化,首先需要了解延遲性需求及可調優的指標有哪些。

  • 應用程式可接受的平均停滯時間: 此時間與測量的Minor
  • GC持續時間進行比較。可接受的Minor GC頻率:Minor
  • GC的頻率與可容忍的值進行比較。
  • 可接受的最大停頓時間:最大停頓時間與最差情況下FullGC的持續時間進行比較。
  • 可接受的最大停頓發生的頻率:基本就是FullGC的頻率。

其中,平均停滯時間和最大停頓時間,對使用者體驗最為重要。對於上面的指標,相關資料採集包括:MinorGC的持續時間、統計MinorGC的次數、FullGC的最差持續時間、最差情況下,FullGC的頻率。

如上圖,Minor GC的平均持續時間0.069秒,MinorGC的頻率為0.389秒一次。

新生代空間越大,Minor GC的GC時間越長,頻率越低。如果想減少其持續時長,就需要減少其空間大小。如果想減小其頻率,就需要加大其空間大小。

這裡以減少了新生代空間10%的大小,來減小延遲時間。在此過程中,應該保持老年代和持代的大小不變化。調優後的引數如下變化:

java -Xms359m -Xmx359m -Xmn126m -XX:PermSize=5m -XX:MaxPermSize=5m

吞吐量調優

吞吐量調優主要是基於應用程式的吞吐量要求而來的,應用程式應該有一個綜合的吞吐指標,這個指標基於整個應用的需求和測試而衍生出來的。

評估當前吞吐量和目標差距是否巨大,如果在20%左右,可以修改引數,加大記憶體,再次從頭除錯,如果巨大就需要從整個應用層面來考慮,設計以及目標是否一致了,重新評估吞吐目標。

對於垃圾收集器來說,提升吞吐量的效能調優的目標就是儘可能避免或者很少發生FullGC或者Stop-The-World壓縮式垃圾收集(CMS),因為這兩種方式都會造成應用程式吞吐降低。儘量在MinorGC 階段回收更多的物件,避免物件提升過快到老年代。

調優工具

藉助GCViewer日誌分析工具,可以非常直觀地分析出待調優點。可從以下幾方面來分析:

Memory,分析Totalheap、Tenuredheap、Youngheap記憶體佔用率及其他指標,理論上記憶體佔用率越小越好;

Pause,分析Gc pause、Fullgc pause、Total pause三個大項中各指標,理論上GC次數越少越好,GC時長越小越好;

原文連結:《JVM效能調優詳解》

本文參考:

(1)https://blog.csdn.net/jisuanjiguoba/article/details/80176223
(2)https://juejin.im/post/59f02f406fb9a0451869f01c

《面試官》系列文章:

  • 《JVM之記憶體結構詳解》
  • 《面試官,不要再問我“Java GC垃圾回收機制”了》
  • 《面試官,Java8 JVM記憶體結構變了,永久代到元空間》
  • 《面試官,不要再問我“Java 垃圾收集器”了》
  • 《Java虛擬機器類載入器及雙親委派機制》
  • 《Java記憶體模型(JMM)詳解》
  • 《Java記憶體模型相關原則詳解》
  • 《JVM效能調優詳解》


程式新視界:精彩和成長都不容錯過

相關推薦

JVM效能調

前面我們學習了整個JVM系列,最終目標的不僅僅是瞭解JVM的基礎知識,也是為了進行JVM效能調優做準備。這篇文章帶領大家學習JVM效能調優的知識。 效能調優 效能調優包含多個層次,比如:架構調優、程式碼調優、JVM調優、資料庫調優、作業系統調優等。 架構調優和程式碼調優是JVM調優的基礎,其中架構調優是對系統

Spark Streaming效能調(轉)

原文連結:Spark Streaming效能調優詳解  Spark Streaming提供了高效便捷的流式處理模式,但是在有些場景下,使用預設的配置達不到最優,甚至無法實時處理來自外部的資料,這時候我們就需要對預設的配置進行相關的修改。由於現實中場景和資料量不一樣,所以我們無法設定一些

JVM效能調監控工具jps、jstack、jmap、jhat、jstat、hprof

來源:https://my.oschina.net/feichexia/blog/196575 現實企業級Java開發中,有時候我們會碰到下面這些問題: OutOfMemoryError,記憶體不足 記憶體洩露 執行緒死鎖 鎖爭用(Lock Contention)

JVM效能調監控工具jps、jstack、jmap、jhat、jstat、hprof使用,以及例子

現實企業級Java開發中,有時候我們會碰到下面這些問題: OutOfMemoryError,記憶體不足 記憶體洩露 執行緒死鎖 鎖爭用(Lock Contention) Java程序消耗CPU過高 ......     這

[JVM]Java生產環境下效能監控與調_Btrace

本章關鍵詞:BTrace、攔截、注意事項 一、入門 1.做什麼的? 可以在應用程式不重啟,不修改的情況下,正在執行的情況下,動態的修改位元組碼,達到監控除錯的目的 可以動態的向目標應用程式的位元組碼注入追蹤程式碼 用到的技術 JavaComplierApi、J

JVM效能調的6大步驟,及關鍵調引數

JVM效能調優的6大步驟,及關鍵調優引數詳解 JVM效能調優方法和步驟 1.監控GC的狀態 2.生成堆的dump檔案 3.分析dump檔案 4.分析結果,判斷是否需要優化 5.調整GC型別和記憶體分配 6.不斷分析

JVM效能調監控工具jps、jstack、jmap、jhat、jstat、hprof使用

第一部分:工具介紹部分: 現實企業級Java開發中,有時候我們會碰到下面這些問題: OutOfMemoryError,記憶體不足 記憶體洩露 執行緒死鎖 鎖爭用(Lock Contention) Java程序消耗CPU過高 ...... 這些問題在日常開發中可能被很多人忽視(比如有的人遇到

JVM效能調監控工具jps、jstack、jstat、jmap、jinfo使用

jcmd命令:主要提供JVM的一些基本資訊查詢(檢視程序執行時間、檢視虛擬機器版本資訊、顯示調優標誌)jinfo命令:檢視程序ID號。檢視JVM的配置引數。jps檢視所有的jvm程序,包括程序ID,程序啟動的路徑等等。我自己也用PS,即:ps -ef | grep javaj

Java生產環境下效能監控與調

第8章 JVM位元組碼與Java程式碼層調優 本章帶大家學習JVM的位元組碼指令,從位元組碼層面講解一些常見問題的底層原理(面試能回答上的話, 絕對加分),比如:i++和++i哪一種效率高?迴圈體中做字串+拼接為什麼效率低?然後會重點對String做講解,包括String常量池的變化、String字面

Java生產環境下效能監控與調 第6章 Nginx效能監控與調

第6章 Nginx效能監控與調優 6-1 nginx安裝 6-2 ngx_http_stub_status監控連線資訊 6-3 ngxtop監控請求資訊 6-4 nginx-rrd圖形化監控

Tomcat調

調整 javase 很多 ews ade 文件的 target 根據 class 前言   在這裏告誡一下那些感覺自己啥都會的朋友們,其實你會的可能只是皮毛,不要感覺這個東西以前已經做過了,就不想去做了   其實你還遠沒有達到精通的地步,遇到以前做過的東西,也要用心的再去做

ifeve.com 南方《JVM 效能調實戰之:使用阿里開源工具 TProfiler 在海量業務程式碼中精確定位效能程式碼》

https://blog.csdn.net/defonds/article/details/52598018 多次拉取 JStack,發現很多執行緒處於這個狀態:    at jrockit/vm/Allocator.getNewTla(JJ)V(Native Method) 

JVM效能調監控工具jps、jstack、jstat、jmap、jinfo使用

 現實企業級Java開發中,有時候我們會碰到下面這些問題: OutOfMemoryError,記憶體不足 記憶體洩露 執行緒死鎖 鎖爭用(Lock Contention) Java程序消耗CPU過高 ...... &n

如何合理的規劃一次jvm效能調

原文中的評論很有參考價值,轉發只是為了以後方便檢視 這是jvm優化系列第三篇: JVM效能調優涉及到方方面面的取捨,往往是牽一髮而動全身,需要全盤考慮各方面的影響。但也有一些基礎的理論和原則,理解這些理論並遵循這些原則會讓你的效能調優任務將會更加輕鬆。為了更好的理解本

深入理解Java虛擬機器(四)——JVM效能調監控工具

Jinfo 檢視正在執行的Java應用程式的擴充套件引數 檢視jvm的引數 檢視java系統引數 Jstat jstat命令可以檢視堆記憶體各部分的使用量,以及載入類的數量。命

spark 引數調(持續更新中)

spark引數調優需要對各個引數充分理解,沒有一套可以借鑑的引數,因為每個叢集規模都不一樣,只有理解了引數的用途,調試出符合自己業務場景叢集環境,並且能在擴大叢集、業務的情況下,能夠跟著修改引數。這樣才算是正確的引數調優。 1、背景 使用spark-thriftser

JVM 效能調實戰之 使用阿里開源工具 TProfiler 在海量業務程式碼中精確定位效能程式碼

                本文是《JVM 效能調優實戰之:一次系統性能瓶頸的尋找過程》 的後續篇,該篇介紹瞭如何使用 JDK 自身提供的工具進行 JVM 調優將 TPS 由 2.5 提升到 20 (提升了 7 倍),並準確定位系統瓶頸:我們應用裡靜態物件不是太多、有大量的業務執行緒在頻繁建立一些生命週期

JVM效能調

 一、JVM記憶體模型及垃圾收集演算法  1.根據Java虛擬機器規範,JVM將記憶體劃分為: New(年輕代)Tenured(年老代)永久代(Perm)  其中New和Tenured屬於堆記憶體,堆記憶體會從JVM啟動引數(-Xmx:3G)指定的記憶體中分配,Perm

tomcat與JVM效能調

tomcat的效能調優是實際生產中很重要的一部分,雖然我們平時在除錯時只要能跑起來就行,但是實際部署之後,當訪問的使用者量一增加,就涉及到tomcat的最大併發量等問題。那麼如何設定tomcat以及JVM,使我們的web應用的併發量增加呢? 一、tomcat記憶體

1分鐘帶你入門JVM效能調

版本:JDK8 一、閱讀前熱身: 1、瞭解jvm啟動流程: 2、瞭解硬體、系統、程序三個層面的記憶體之間的概要記憶體分配,一張圖你就懂: 3、下面是需要背住的重點,敲黑板!!堆記憶體分配,想了解引數的可以到最下面看下備註和建議: 先來個日誌(看