JVM監控與調優

1、JVM內存及參數設置php

-Xmn
新生代內存大小的最大值,包括E區和兩個S區的總和,使用方法如:-Xmn65535,-Xmn1024k,-Xmn512m,-Xmn1g (-Xms,-Xmx也是種寫法)
-Xmn只能使用在JDK1.4或以後的版本中,(以前的1.3/1.4版本中,可以使用-XX:NewSize設置年輕代大小,用-XX:MaxNewSize設置年輕代最大值);
若是同時設置了-Xmn和-XX:NewSize,-XX:MaxNewSize,則誰設置在後面,誰就生效;若是同時設置了-XX:NewSize -XX:MaxNewSize與-XX:NewRatio則實際生效的值是:min(MaxNewSize,max(NewSize, heap/(NewRatio+1)))(看考:http://www.open-open.com/home/space.php?uid=71669&do=blog&id=8891)
在開發、測試環境,能夠-XX:NewSize 和 -XX:MaxNewSize來設置新生代大小,但在線上生產環境,使用-Xmn一個便可(推薦),或者將-XX:NewSize 和 -XX:MaxNewSize設置爲同一個值,這樣可以防止在每次GC以後都要調整堆的大小(即:抖動,抖動會嚴重影響性能)

 -Xms
初始堆的大小,也是堆大小的最小值,默認值是總共的物理內存/64(且小於1G),默認狀況下,當堆中可用內存小於40%(這個值能夠用-XX: MinHeapFreeRatio 調整,如-X:MinHeapFreeRatio=30)時,堆內存會開始增長,一直增長到-Xmx的大小;

 -Xmx
堆的最大值,默認值是總共的物理內存/64(且小於1G),若是Xms和Xmx都不設置,則二者大小會相同,默認狀況下,當堆中可用內存大於70%(這個值能夠用-XX: MaxHeapFreeRatio 調整,如-X:MaxHeapFreeRatio=60)時,堆內存會開始減小,一直減少到-Xms的大小;
整個堆的大小=年輕代大小+年老代大小,堆的大小不包含持久代大小,若是增大了年輕代,年老代相應就會減少,官方默認的配置爲年老代大小/年輕代大小=2/1左右(使用-XX:NewRatio能夠設置-XX:NewRatio=5,表示年老代/年輕代=5/1);
建議在開發測試環境能夠用Xms和Xmx分別設置最小值最大值,可是在線上生產環境,Xms和Xmx設置的值必須同樣,緣由與年輕代同樣——防止抖動;

 -Xss
這個參數用於設置每一個線程的棧內存,默認1M,通常來講是不須要改的。除非代碼很少,能夠設置的小點,另一個類似的參數是-XX:ThreadStackSize,這兩個參數在1.6之前,都是誰設置在後面,誰就生效;1.6版本之後,-Xss設置在後面,則以-Xss爲準,-XXThreadStackSize設置在後面,則主線程以-Xss爲準,其它線程以-XX:ThreadStackSize爲準。

 -Xrs
減小JVM對操做系統信號(OS Signals)的使用(JDK1.3.1以後纔有效),當此參數被設置以後,jvm將不接收控制檯的控制handler,以防止與在後臺以服務形式運行的JVM衝突;

-Xprof
 跟蹤正運行的程序,並將跟蹤數據在標準輸出輸出;適合於開發環境調試。

-Xnoclassgc
 關閉針對class的gc功能;由於其阻止內存回收,因此可能會致使OutOfMemoryError錯誤,慎用;

-Xincgc
 開啓增量gc(默認爲關閉);這有助於減小長時間GC時應用程序出現的停頓;但因爲可能和應用程序併發執行,因此會下降CPU對應用的處理能力。

-Xloggc:file
 與-verbose:gc功能相似,只是將每次GC事件的相關狀況記錄到一個文件中,文件的位置最好在本地,以免網絡的潛在問題。
 若與verbose命令同時出如今命令行中,則以-Xloggc爲準。
html

比較詳細的非Stable參數總結,請參考Java 6 JVM參數選項大全(中文版)
對於非Stable參數,使用方法有4種:
java

    • -XX:+<option> 啓用選項
    • -XX:-<option> 不啓用選項
    • -XX:<option>=<number> 給選項設置一個數字類型值,可跟單位,例如 32k, 1024m, 2g
    • -XX:<option>=<string> 給選項設置一個字符串值,例如-XX:HeapDumpPath=./dump.core

首先介紹性能參數,性能參數每每用來定義內存分配的大小和比例,相比於行爲參數和調試參數,一個比較明顯的區別是性能參數後面每每跟的有數值,經常使用以下:服務器

參數及其默認值 描述
-XX:NewSize=2.125m
新生代對象生成時佔用內存的默認值
-XX:MaxNewSize=size 新生成對象能佔用內存的最大值
-XX:MaxPermSize=64m 方法區所能佔用的最大內存(非堆內存)
-XX:PermSize=64m 方法區分配的初始內存
-XX:MaxTenuringThreshold=15
對象在新生代存活區切換的次數(堅持過MinorGC的次數,每堅持過一次,該值就增長1),大於該值會進入老年代
-XX:MaxHeapFreeRatio=70
GC後java堆中空閒量佔的最大比例,大於該值,則堆內存會減小
-XX:MinHeapFreeRatio=40 GC後java堆中空閒量佔的最小比例,小於該值,則堆內存會增長
-XX:NewRatio=2 新生代內存容量與老生代內存容量的比例
-XX:ReservedCodeCacheSize= 32m 保留代碼佔用的內存容量
-XX:ThreadStackSize=512 設置線程棧大小,若爲0則使用系統默認值
-XX:LargePageSizeInBytes=4m
設置用於Java堆的大頁面尺寸
-XX:PretenureSizeThreshold= size    大於該值的對象直接晉升入老年代(這種對象少用爲好)
-XX:SurvivorRatio=8 Eden區域Survivor區的容量比值,如默認值爲8,表明Eden:Survivor1:Survivor2=8:1:1

 

經常使用的行爲參數,主要用來選擇使用什麼樣的垃圾收集器組合,以及控制運行過程當中的GC策略等:網絡

參數及其默認值 描述
-XX:-UseSerialGC
啓用串行GC,即採用Serial+Serial Old模式
-XX:-UseParallelGC
啓用並行GC,即採用Parallel Scavenge+Serial Old收集器組合(-Server模式下的默認組合)
-XX:GCTimeRatio=99 設置用戶執行時間佔總時間的比例(默認值99,即1%的時間用於GC)
-XX:MaxGCPauseMillis=time 設置GC的最大停頓時間(這個參數只對Parallel Scavenge有效)
-XX:+UseParNewGC 使用ParNew+Serial Old收集器組合
-XX:ParallelGCThreads 設置執行內存回收的線程數,在+UseParNewGC的狀況下使用
-XX:+UseParallelOldGC
使用Parallel Scavenge +Parallel Old組合收集器
-XX:+UseConcMarkSweepGC 使用ParNew+CMS+Serial Old組合併發收集,優先使用ParNew+CMS,當用戶線程內存不足時,採用備用方案Serial Old收集。
-XX:-DisableExplicitGC 禁止調用System.gc();但jvm的gc仍然有效
-XX:+ScavengeBeforeFullGC 新生代GC優先於Full GC執行

 

經常使用的調試參數,主要用於監控和打印GC的信息:併發

參數及其默認值 描述
-XX:-CITime 打印消耗在JIT編譯的時間
-XX:ErrorFile=./hs_err_pid<pid>.log 保存錯誤日誌或者數據到文件中
-XX:-ExtendedDTraceProbes 開啓solaris特有的dtrace探針
-XX:HeapDumpPath=./java_pid<pid>.hprof 指定導出堆信息時的路徑或文件名
-XX:-HeapDumpOnOutOfMemoryError 當首次遭遇OOM時導出此時堆中相關信息
-XX:OnError="<cmd args>;<cmd args>" 出現致命ERROR以後運行自定義命令
-XX:OnOutOfMemoryError="<cmd args>;<cmd args>" 當首次遭遇OOM時執行自定義命令
-XX:-PrintClassHistogram 遇到Ctrl-Break後打印類實例的柱狀信息,與jmap -histo功能相同
-XX:-PrintConcurrentLocks 遇到Ctrl-Break後打印併發鎖的相關信息,與jstack -l功能相同
-XX:-PrintCommandLineFlags 打印在命令行中出現過的標記
-XX:-PrintCompilation 當一個方法被編譯時打印相關信息
-XX:-PrintGC 每次GC時打印相關信息
-XX:-PrintGC Details 每次GC時打印詳細信息
-XX:-PrintGCTimeStamps 打印每次GC的時間戳
-XX:-TraceClassLoading 跟蹤類的加載信息
-XX:-TraceClassLoadingPreorder 跟蹤被引用到的全部類的加載信息
-XX:-TraceClassResolution 跟蹤常量池
-XX:-TraceClassUnloading 跟蹤類的卸載信息
-XX:-TraceLoaderConstraints 跟蹤類加載器約束的相關信息

2、啓動內存分配jvm

關於GC有一個常見的疑問是,在啓動時,個人內存如何分配?通過前面的學習,已經很容易知道,用-Xmn,-Xmx,-Xms,-Xss,-XX:NewSize,-XX:MaxNewSize,-XX:MaxPermSize,-XX:PermSize,-XX:SurvivorRatio,-XX:PretenureSizeThreshold,-XX:MaxTenuringThreshold就基本能夠配置內存啓動時的分配狀況。可是,具體配置多少?設置小了,頻繁GC(甚至內存溢出),設置大了,內存浪費。結合前面對於內存區域和其做用的學習,儘可能考慮以下建議:工具

  1. -XX:PermSize儘可能比-XX:MaxPermSize小,-XX:MaxPermSize>= 2 * -XX:PermSize, -XX:PermSize> 64m,通常對於4G內存的機器,-XX:MaxPermSize不會超過256m;
  2. -Xms =  -Xmx(線上Server模式),以防止抖動,大小受操做系統和內存大小限制,若是是32位系統,則通常-Xms設置爲1g-2g(假設有4g內存),在64位系統上,沒有限制,不過通常爲機器最大內存的一半左右;
  3. -Xmn,在開發環境下,能夠用-XX:NewSize和-XX:MaxNewSize來設置新生代的大小(-XX:NewSize<=-XX:MaxNewSize),在生產環境,建議只設置-Xmn,通常-Xmn的大小是-Xms的1/2左右,不要設置的過大或太小,過大致使老年代變小,頻繁Full GC,太小致使minor GC頻繁。若是不設置-Xmn,能夠採用-XX:NewRatio=2來設置,也是同樣的效果;
  4. -Xss通常是不須要改的,默認值便可。
  5. -XX:SurvivorRatio通常設置8-10左右,推薦設置爲10,也即:Survivor區的大小是Eden區的1/10,通常來講,普通的Java程序應用,一次minorGC後,至少98%-99%的對象,都會消亡,因此,survivor區設置爲Eden區的1/10左右,能使Survivor區容納下10-20次的minor GC才滿,而後再進入老年代,這個與 -XX:MaxTenuringThreshold的默認值15次也相匹配的。若是XX:SurvivorRatio設置的過小,會致使原本能經過minor回收掉的對象提早進入老年代,產生沒必要要的full gc;若是XX:SurvivorRatio設置的太大,會致使Eden區相應的被壓縮。
  6. -XX:MaxTenuringThreshold默認爲15,也就是說,通過15次Survivor輪換(即15次minor GC),就進入老年代, 若是設置的小的話,則年輕代對象在survivor中存活的時間減少,提早進入年老代,對於年老代比較多的應用,能夠提升效率。若是將此值設置爲一個較大值,則年輕代對象會在Survivor區進行屢次複製,這樣能夠增長對象在年輕代的存活時間,增長在年輕代即被回收的機率。須要注意的是,設置了  -XX:MaxTenuringThreshold,並不表明着,對象必定在年輕代存活15次才被晉升進入老年代,它只是一個最大值,事實上,存在一個動態計算機制,計算每次晉入老年代的閾值,取閾值和MaxTenuringThreshold中較小的一個爲準。
  7. -XX:PretenureSizeThreshold通常採用默認值便可。

參見:http://my.oschina.net/chape/blog/200790?fromerr=t037M1rv性能

調優方法學習

一切都是爲了這一步,調優,在調優以前,咱們須要記住下面的原則:

  1. 多數的Java應用不須要在服務器上進行GC優化;
  2. 多數致使GC問題的Java應用,都不是由於咱們參數設置錯誤,而是代碼問題;
  3. 在應用上線以前,先考慮將機器的JVM參數設置到最優(最適合);
  4. 減小建立對象的數量;
  5. 減小使用全局變量和大對象;
  6. GC優化是到最後不得已才採用的手段;
  7. 在實際使用中,分析GC狀況優化代碼比優化GC參數要多得多;

GC優化的目的有兩個(http://www.360doc.com/content/13/0305/10/15643_269388816.shtml):

  • 將轉移到老年代的對象數量下降到最小;
  • 減小full GC的執行時間;

爲了達到上面的目的,通常地,你須要作的事情有:

  • 減小使用全局變量和大對象;
  • 調整新生代的大小到最合適;
  • 設置老年代的大小爲最合適;
  • 選擇合適的GC收集器;

在上面的4條方法中,用了幾個「合適」,那究竟什麼纔算合適,通常的,請參考上面「收集器搭配」和「啓動內存分配」兩節中的建議。但這些建議不是萬能的,須要根據您的機器和應用狀況進行發展和變化,實際操做中,能夠將兩臺機器分別設置成不一樣的GC參數,而且進行對比,選用那些確實提升了性能或減小了GC時間的參數。

真正熟練的使用GC調優,是創建在屢次進行GC監控和調優的實戰經驗上的,進行監控和調優的通常步驟爲:
1,監控GC的狀態
使用各類JVM工具,查看當前日誌,分析當前JVM參數設置,而且分析當前堆內存快照和gc日誌,根據實際的各區域內存劃分和GC執行時間,以爲是否進行優化;
2,分析結果,判斷是否須要優化
若是各項參數設置合理,系統沒有超時日誌出現,GC頻率不高,GC耗時不高,那麼沒有必要進行GC優化;若是GC時間超過1-3秒,或者頻繁GC,則必須優化;
注:若是知足下面的指標,則通常不須要進行GC:

 

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

3,調整GC類型和內存分配
若是內存分配過大或太小,或者採用的GC收集器比較慢,則應該優先調整這些參數,而且先找1臺或幾臺機器進行beta,而後比較優化過的機器和沒有優化的機器的性能對比,並有針對性的作出最後選擇;
4,不斷的分析和調整
經過不斷的試驗和試錯,分析並找到最合適的參數
5,全面應用參數
若是找到了最合適的參數,則將這些參數應用到全部服務器,並進行後續跟蹤。

調優實例

上面的內容都是紙上談兵,下面咱們以一些真實例子來進行說明:
實例1:
筆者昨日發現部分開發測試機器出現異常:java.lang.OutOfMemoryError: GC overhead limit exceeded,這個異常表明:GC爲了釋放很小的空間卻耗費了太多的時間,其緣由通常有兩個:1,堆過小,2,有死循環或大對象;
筆者首先排除了第2個緣由,由於這個應用同時是在線上運行的,若是有問題,早就掛了。因此懷疑是這臺機器中堆設置過小;
使用ps -ef |grep "java"查看,發現:


該應用的堆區設置只有768m,而機器內存有2g,機器上只跑這一個java應用,沒有其餘須要佔用內存的地方。另外,這個應用比較大,須要佔用的內存也比較多;
筆者經過上面的狀況判斷,只須要改變堆中各區域的大小設置便可,因而改爲下面的狀況:

 


跟蹤運行狀況發現,相關異常沒有再出現;

實例2:(http://www.360doc.com/content/13/0305/10/15643_269388816.shtml)
一個服務系統,常常出現卡頓,分析緣由,發現Full GC時間太長:
jstat -gcutil:
S0     S1    E     O       P        YGC YGCT FGC FGCT  GCT
12.16 0.00 5.18 63.78 20.32  54   2.047 5     6.946  8.993 
分析上面的數據,發現Young GC執行了54次,耗時2.047秒,每次Young GC耗時37ms,在正常範圍,而Full GC執行了5次,耗時6.946秒,每次平均1.389s,數據顯示出來的問題是:Full GC耗時較長,分析該系統的是指發現,NewRatio=9,也就是說,新生代和老生代大小之比爲1:9,這就是問題的緣由:
1,新生代過小,致使對象提早進入老年代,觸發老年代發生Full GC;
2,老年代較大,進行Full GC時耗時較大;
優化的方法是調整NewRatio的值,調整到4,發現Full GC沒有再發生,只有Young GC在執行。這就是把對象控制在新生代就清理掉,沒有進入老年代(這種作法對一些應用是頗有用的,但並非對全部應用都要這麼作)

實例3:
一應用在性能測試過程當中,發現內存佔用率很高,Full GC頻繁,使用sudo -u admin -H  jmap -dump:format=b,file=文件名.hprof pid 來dump內存,生成dump文件,並使用Eclipse下的mat差距進行分析,發現:

 

從圖中能夠看出,這個線程存在問題,隊列LinkedBlockingQueue所引用的大量對象並未釋放,致使整個線程佔用內存高達378m,此時通知開發人員進行代碼優化,將相關對象釋放掉便可。

相關文章
相關標籤/搜索