JVM調優總結

來源:互聯網
上載者:User

標籤:epo   除了   圖形   出現   處理   是什麼   serial   world   network   

 

寫在之前的話

最近在工作中總是遇到服務的QPS在壓測的時間比較低的情況。於是就開始了效能最佳化之旅,這個過程是很是曲折。一開始的時候認為是服務的商務邏輯比較多,大部分的時間都花在最佳化商務邏輯,減少與其他服務和資料庫等介面的調用,使用緩衝等方式提高效能。上述的工作都是對效能有提升的,但是對於一個熟練的農民工而言,對語言的特性已經成竹在胸,很難通過最佳化一兩句代碼獲得質的提升。由於目前都是採用微服務的開發方式,JVM的參數是自己設定的,就想著在這個方面去最佳化一下。

通過在壓測過程中檢測(使用jstat工具)gc的次數及時間來分析,這個服務在壓力測試中的gc次數已經到了影響提升效能的關鍵因素。於是便著手減少gc的次數。

本次最佳化的目的有兩個

1、將轉移到老年代的對象數量降低到最小;

2、減少full GC的執行時間;

從網上看了一些JVM調優的方法,其中一位仁兄分享的程式調優方法覺得跟自己的情況特別服務,特別的在這裡跟大家分享下:

一切都是為了這一步,調優,在調優之前,我們需要記住下面的原則:

1、多數的Java應用不需要在伺服器上進行GC最佳化;

2、多數導致GC問題的Java應用,都不是因為我們參數設定錯誤,而是代碼問題;

3、在應用上線之前,先考慮將機器的JVM參數設定到最優(最適合);

4、減少建立對象的數量;

5、減少使用全域變數和大對象;

6GC最佳化是到最後不得已才採用的手段;

7、在實際使用中,分析GC情況最佳化代碼比最佳化GC參數要多得多;

為了達到上面的目的,一般地,你需要做的事情有:

1、減少使用全域變數和大對象;

2、調整新生代的大小到最合適;

3、設定老年代的大小為最合適;

4、選擇合適的GC收集器;

JVM堆棧組成及劃分

有了上面的思路,下面我們一起來瞭解下JVM堆棧的結構。JVM堆棧由三部分組成:新生代、老年代和永久代。形象的描述了各個區的劃分:

我們可以看出堆記憶體空間的結構

1. JVM堆記憶體由三大區組成:新生代(Yong Generation)、老年代(Tenured Generation)和永久帶(Perm Generation);

2. 新生代由三部分組成:一個Eden區、兩個Survivor區;

3. 兩個Survivor區一個叫From,一個叫To,從字面叫法上可以看出兩個的作用;

4. Eden和Survivor預設比例是8:1。一般情況下,新建立的對象都會被分配到Eden區(一些大對象特殊處理),這些對象經過第一次Minor GC後,如果仍然存活,將會被移到Survivor區。對象在Survivor區中每熬過一次Minor GC,年齡就會增加1歲,當它的年齡增加到一定程度時,就會被移動到年老代中。

GC過程中對象的移動過程

在GC開始的時候,對象只會存在於Eden區和名為“From”的Survivor區,Survivor區“To”是空的。緊接著進行GC,Eden區中所有存活的對象都會被複製到“To”,而在“From”區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設定)的對象會被移動到年老代中,沒有達到閾值的對象會被複製到“To”地區。經過這次GC後,Eden區和From區已經被清空。這個時候,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名為To的Survivor地區是空的。Minor GC會一直重複這樣的過程,直到“To”區被填滿,“To”區被填滿之後,會將所有對象移動到年老代中。

JVM運行時關鍵參數設定

參數名稱

說明

Tip

-Xms

堆的最小值

32位系統 下,一般限制在1.5G~2G;64為作業系統對記憶體無限制

-Xmx

堆空間的最大值

32位系統 下,一般限制在1.5G~2G;64為作業系統對記憶體無限制

-Xmn

年輕代大小

整個堆大小=年輕代大小 + 年老代大小 + 持久代大小 。持久代一般固定大小為64m,所以增大年輕代後,將會減小年老代大小。此值對系統效能影響較大,Sun官方推薦配置為整個堆的3/8。

-Xss

設定每個線程的堆棧大小

JDK5.0以後每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需記憶體大小進行調整。在相同物理內 存下,減小這個值能產生更多的線程。但是作業系統對一個進程內的線程數還是有限制的,不能無限產生,經驗值在3000~5000左右。

-Xms

堆的最小值

32位系統 下,一般限制在1.5G~2G;64為作業系統對記憶體無限制

有關年輕代的JVM參數

1) -XX:NewSize和-XX:MaxNewSize

用於設定年輕代的大小,建議設為整個堆大小的1/3或者1/4,兩個值設為一樣大。

2) -XX:SurvivorRatio

用於設定Eden和其中一個Survivor的比值,這個值也比較重要。設定年輕代中Eden區與Survivor區的大小比值。設定為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區占整個年輕代的1/6

3) -XX:NewRatio=4

設定年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設定為4,則年輕代與年老代所佔比值為1:4,年輕代占整個堆棧的1/5

4) -XX:+PrintTenuringDistribution

這個參數用於顯示每次Minor GC時Survivor區中各個年齡段的對象的大小。

5) -XX:MaxPermSize=16m

建議設定持久代大小為16m。

6) -XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold

用於設定晉陞到老年代的對象年齡的最小值和最大值,每個對象在堅持過一次Minor GC之後,年齡就加1。

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

輸送量收集器

1) -XX:+UseSerialGC

啟用串列垃圾收集器 例如單線程面向輸送量的垃圾收集器 推薦用於只有單個CPU的JVM

2) -XX:+UseParallelGC

使用多線程並存執行年輕代垃圾收集

3) -XX:+UseParallelOldG

除了啟用年輕代並行垃圾收集,也啟用了年老代並行垃圾收集

4) -XX:ParallelGCThreads

-XX:ParallelGCThreads=<value> 指定並行垃圾收集的線程數量

5) -XX:-UseAdaptiveSizePolicy

垃圾收集器能將堆大小動態變動像GC設定一樣應用到不同的堆地區,只要有證據表明這些變動將能提高GC效能

6) -XX:GCTimeRatio

-XX:GCTimeRatio=<value>指定JVM輸送量要達到的目標值
指定目標應用程式線程的執行時間和總的程式執行時間達到N/(N+1)的目標比值
通過-XX:GCTimeRatio=9我們要求應用程式線程在整個執行時間中至少9/10是活動的(因此,GC線程佔用其餘1/10)
-XX:GCTimeRatio的預設值是99,也就是說,應用程式線程應該運行至少99%的總執行時間

7) -XX:MaxGCPauseMillis

通過-XX:GCTimeRatio=<value>告訴JVM最大暫停時間目標值[ms為單位]

CMS收集器

1) -XX:+UseConcMarkSweepGC

啟用CMS收集器 JVM預設使用的是平行處理器

2) -XX:UseParNewGC

使用CMS收集器時 啟用年輕代使用多線程並存執行記憶體回收
注意:
最新的JVM版本,當使用-XX:+UseConcMarkSweepGC時,-XX:UseParNewGC會自動開啟。
因此,如果年輕代的並行GC不想開啟,可以通過設定-XX:-UseParNewGC來關掉。

3) -XX:+CMSConcurrentMTEnabled

並發的CMS階段以多線程執行 預設開啟

4) -XX:ConcGCThreads

-XX:ConcGCThreads=<value>定義並發CMS中啟動並執行線程數
如果還標誌未設定,JVM會根據並行收集器中的-XX:ParallelGCThreads參數的值來計算出預設的並行CMS線程數。該公式是ConcGCThreads = (ParallelGCThreads + 3)/4。因此,對於CMS收集器
-XX:ParallelGCThreads標誌不僅影響“stop-the-world”垃圾收集階段,還影響並發階段。

5) -XX:CMSInitiatingOccupancyFraction

-XX:CMSInitiatingOccupancyFraction=來設定,該值代表老年代堆空間的使用率。比如,value=75意味著第一次CMS垃圾收集會在老年代被佔用75%時被觸發。通常CMSInitiatingOccupancyFraction的預設值為68(之前很長時間的經曆來決定的)。

6) -XX:+UseCMSInitiatingOccupancyOnly

命令JVM不基於運行時收集的資料來啟動CMS垃圾收集周期
JVM通過CMSInitiatingOccupancyFraction的值進行每一次CMS收集,而不僅僅是第一次

7) -XX:+CMSClassUnloadingEnabled

CMS預設不會對永久代進行記憶體回收 如果希望對永久代進行記憶體回收 可以設定此標誌
注意,即使沒有設定這個標誌,一旦永久代耗盡空間也會嘗試進行記憶體回收,但是收集不會是並行的,而再一次進行Full GC。

8) -XX:+CMSIncrementalMode

開啟CMS收集器的增量模式
ps:增量模式會經常暫停CMS過程 以便對應用程式作出完全的讓步

9) -XX:+ExplicitGCInvokesConcurrent和-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses

1.-XX:+ExplicitGCInvokesConcurrent
命令JVM無論什麼時候調用系統GC,都執行CMS GC,而不是Full GC
2.-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
保證當有系統GC調用時,永久代也被包括進CMS記憶體回收的範圍內。因此,通過使用這些標誌,我們可以防止出現意料之外的”stop-the-world”的系統GC。

10) -XX:+DisableExplicitGC

該標誌將告訴JVM完全忽略系統的GC調用(不管使用的收集器是什麼類型)

總結

JVM參數是死的,你的服務所對應的情境才是活的。在調優的過程中需要根據自己的業務需要不斷的調整參數、測試、再調整的迭代方式直到效能達到最優。

推薦大家使用jstat這款Java自動的檢測GC的工具,對於查看系統的GC資訊有很大的協助。

參考資料

官方提供的JVM參數一覽表:

http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

51544977

JVM調優總結

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.