日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java系列笔记(4) - JVM监控与调优【转】

發(fā)布時(shí)間:2023/11/30 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java系列笔记(4) - JVM监控与调优【转】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Java系列筆記(4) - JVM監(jiān)控與調(diào)優(yōu)【轉(zhuǎn)】

目錄

參數(shù)設(shè)置
收集器搭配
啟動(dòng)內(nèi)存分配
監(jiān)控工具和方法
調(diào)優(yōu)方法
調(diào)優(yōu)實(shí)例
??? ?
光說(shuō)不練假把式,學(xué)習(xí)Java GC機(jī)制的目的是為了實(shí)用,也就是為了在JVM出現(xiàn)問(wèn)題時(shí)分析原因并解決之。通過(guò)學(xué)習(xí),我覺(jué)得JVM監(jiān)控與調(diào)優(yōu)主要的著眼點(diǎn)在于如何配置、如何監(jiān)控、如何優(yōu)化3點(diǎn)上。下面就將針對(duì)這3點(diǎn)進(jìn)行學(xué)習(xí)。
?????(如果您對(duì)Java的內(nèi)存區(qū)域劃分和內(nèi)存回收機(jī)制尚不明確,那在閱讀本文前,請(qǐng)先閱讀我的前一篇博客《Java系列筆記(3) - Java 內(nèi)存區(qū)域和GC機(jī)制》,在該博客中,詳細(xì)敘述了Java HotSpot虛擬機(jī)(Sun/Oracle JDK系列默認(rèn)的虛擬機(jī))的內(nèi)存分配和垃圾回收機(jī)制。本文很多內(nèi)容將依據(jù)上一篇博客,同時(shí),本文所針對(duì)的虛擬機(jī),也是HotSpot虛擬機(jī)。)
參數(shù)設(shè)置


?在Java虛擬機(jī)的參數(shù)中,有3種表示方法(出自:http://www.cnblogs.com/wenfeng762/archive/2011/08/14/2137810.html),用“ps -ef |grep "java"命令,可以得到當(dāng)前Java進(jìn)程的所有啟動(dòng)參數(shù)和配置參數(shù):

  • 標(biāo)準(zhǔn)參數(shù)(-),所有的JVM實(shí)現(xiàn)都必須實(shí)現(xiàn)這些參數(shù)的功能,而且向后兼容;
  • 非標(biāo)準(zhǔn)參數(shù)(-X),默認(rèn)jvm實(shí)現(xiàn)這些參數(shù)的功能,但是并不保證所有jvm實(shí)現(xiàn)都滿(mǎn)足,且不保證向后兼容;
  • 非Stable參數(shù)(-XX),此類(lèi)參數(shù)各個(gè)jvm實(shí)現(xiàn)會(huì)有所不同,將來(lái)可能會(huì)隨時(shí)取消,需要慎重使用(但是,這些參數(shù)往往是非常有用的);

(額外的,-DpropertyName=“value”的形式定義了一些全局屬性值,下面有介紹。)
本文只重點(diǎn)介紹一些重要和常用的參數(shù),如果想了解全部參數(shù),可以參考下面的文章:

《Java HotSpot VM Options》 《Java 6 JVM參數(shù)選項(xiàng)大全(中文版)》(上面一篇的中文版) 《JVM啟動(dòng)參數(shù)大全》 標(biāo)準(zhǔn)參數(shù)

其實(shí)標(biāo)準(zhǔn)參數(shù)是用過(guò)Java的人都最熟悉的,就是你在運(yùn)行java命令時(shí)后面加上的參數(shù),如java -version, java -jar 等,輸入命令java -help或java -?就能獲得當(dāng)前機(jī)器所有java的標(biāo)準(zhǔn)參數(shù)列表。
-client
設(shè)置jvm使用client模式,這是一般在pc機(jī)器上使用的模式,啟動(dòng)很快,但性能和內(nèi)存管理效率并不高;多用于桌面應(yīng)用;

-server
使用server模式,啟動(dòng)速度雖然慢(比client模式慢10%左右),但是性能和內(nèi)存管理效率很高,適用于服務(wù)器,用于生成環(huán)境、開(kāi)發(fā)環(huán)境或測(cè)試環(huán)境的服務(wù)端;
如果沒(méi)有指定-server或-client,JVM啟動(dòng)的時(shí)候會(huì)自動(dòng)檢測(cè)當(dāng)前主機(jī)是否為服務(wù)器,如果是就以server模式啟動(dòng),64位的JVM只有server模式,所以無(wú)法使用-client參數(shù);
默認(rèn)情況下,不同的啟動(dòng)模式,執(zhí)行GC的方式有所區(qū)別:

啟動(dòng)模式新生代GC方式舊生代和持久代GC的方式
client串行串行
server并行并發(fā)

如果沒(méi)有指定-server或-client模式,則判斷方法如下:

-classpath / -cp
JVM加載和搜索文件的目錄路徑,多個(gè)路徑用;分隔。注意,如果使用了-classpath,JVM就不會(huì)再搜索環(huán)境變量中定義的CLASSPATH路徑。
JVM搜索路徑的順序?yàn)?#xff1a;
1,先搜索JVM自帶的jar或zip包(Bootstrat,搜索路徑可以用System.getProperty("sun.boot.class.path")獲得);
2,搜索JRE_HOME/lib/ext下的jar包(Extension,搜索路徑可以用System.getProperty("java.ext.dirs")獲得);
3,搜索用戶(hù)自定義目錄,順序?yàn)?#xff1a;當(dāng)前目錄(.),CLASSPATH,-cp;(搜索路徑用System.getProperty("java.class.path")獲得)

-DpropertyName=value
定義系統(tǒng)的全局屬性值,如配置文件地址等,如果value有空格,可以用-Dname="space string"這樣的形式來(lái)定義,用System.getProperty("propertyName")可以獲得這些定義的屬性值,在代碼中也可以用System.setProperty("propertyName","value")的形式來(lái)定義屬性。

-verbose?
這是查詢(xún)GC問(wèn)題最常用的命令之一,具體參數(shù)如:
-verbose:class
?輸出jvm載入類(lèi)的相關(guān)信息,當(dāng)jvm報(bào)告說(shuō)找不到類(lèi)或者類(lèi)沖突時(shí)可此進(jìn)行診斷。
-verbose:gc
?輸出每次GC的相關(guān)情況,后面會(huì)有更詳細(xì)的介紹。
-verbose:jni
?輸出native方法調(diào)用的相關(guān)情況,一般用于診斷jni調(diào)用錯(cuò)誤信息。

非標(biāo)準(zhǔn)參數(shù)
非標(biāo)準(zhǔn)參數(shù),是在標(biāo)準(zhǔn)參數(shù)的基礎(chǔ)上進(jìn)行擴(kuò)展的參數(shù),輸入“java -X”命令,能夠獲得當(dāng)前JVM支持的所有非標(biāo)準(zhǔn)參數(shù)列表(你會(huì)發(fā)現(xiàn),其實(shí)并不多哦)。

在不同類(lèi)型的JVM中,采用的參數(shù)有所不同,
在講解非標(biāo)準(zhǔn)參數(shù)時(shí),請(qǐng)參考下面的圖,對(duì)內(nèi)存區(qū)域的大小有個(gè)形象的了解(下圖出自:http://iamzhongyong.iteye.com/blog/1333100):


-Xmn
新生代內(nèi)存大小的最大值,包括E區(qū)和兩個(gè)S區(qū)的總和,使用方法如:-Xmn65535,-Xmn1024k,-Xmn512m,-Xmn1g (-Xms,-Xmx也是種寫(xiě)法)
-Xmn只能使用在JDK1.4或之后的版本中,(之前的1.3/1.4版本中,可使用-XX:NewSize設(shè)置年輕代大小,用-XX:MaxNewSize設(shè)置年輕代最大值);
如果同時(shí)設(shè)置了-Xmn和-XX:NewSize,-XX:MaxNewSize,則誰(shuí)設(shè)置在后面,誰(shuí)就生效;如果同時(shí)設(shè)置了-XX:NewSize -XX:MaxNewSize與-XX:NewRatio則實(shí)際生效的值是:min(MaxNewSize,max(NewSize, heap/(NewRatio+1)))(看考:http://www.open-open.com/home/space.php?uid=71669&do=blog&id=8891)
在開(kāi)發(fā)、測(cè)試環(huán)境,可以-XX:NewSize 和 -XX:MaxNewSize來(lái)設(shè)置新生代大小,但在線(xiàn)上生產(chǎn)環(huán)境,使用-Xmn一個(gè)即可(推薦),或者將-XX:NewSize 和 -XX:MaxNewSize設(shè)置為同一個(gè)值,這樣能夠防止在每次GC之后都要調(diào)整堆的大小(即:抖動(dòng),抖動(dòng)會(huì)嚴(yán)重影響性能)

?-Xms
初始堆的大小,也是堆大小的最小值,默認(rèn)值是總共的物理內(nèi)存/64(且小于1G),默認(rèn)情況下,當(dāng)堆中可用內(nèi)存小于40%(這個(gè)值可以用-XX: MinHeapFreeRatio 調(diào)整,如-X:MinHeapFreeRatio=30)時(shí),堆內(nèi)存會(huì)開(kāi)始增加,一直增加到-Xmx的大小;

?-Xmx
堆的最大值,默認(rèn)值是總共的物理內(nèi)存/64(且小于1G),如果Xms和Xmx都不設(shè)置,則兩者大小會(huì)相同,默認(rèn)情況下,當(dāng)堆中可用內(nèi)存大于70%(這個(gè)值可以用-XX: MaxHeapFreeRatio 調(diào)整,如-X:MaxHeapFreeRatio=60)時(shí),堆內(nèi)存會(huì)開(kāi)始減少,一直減小到-Xms的大小;
整個(gè)堆的大小=年輕代大小+年老代大小,堆的大小不包含持久代大小,如果增大了年輕代,年老代相應(yīng)就會(huì)減小,官方默認(rèn)的配置為年老代大小/年輕代大小=2/1左右(使用-XX:NewRatio可以設(shè)置-XX:NewRatio=5,表示年老代/年輕代=5/1);
建議在開(kāi)發(fā)測(cè)試環(huán)境可以用Xms和Xmx分別設(shè)置最小值最大值,但是在線(xiàn)上生產(chǎn)環(huán)境,Xms和Xmx設(shè)置的值必須一樣,原因與年輕代一樣——防止抖動(dòng);

?-Xss
這個(gè)參數(shù)用于設(shè)置每個(gè)線(xiàn)程的棧內(nèi)存,默認(rèn)1M,一般來(lái)說(shuō)是不需要改的。除非代碼不多,可以設(shè)置的小點(diǎn),另外一個(gè)相似的參數(shù)是-XX:ThreadStackSize,這兩個(gè)參數(shù)在1.6以前,都是誰(shuí)設(shè)置在后面,誰(shuí)就生效;1.6版本以后,-Xss設(shè)置在后面,則以-Xss為準(zhǔn),-XXThreadStackSize設(shè)置在后面,則主線(xiàn)程以-Xss為準(zhǔn),其它線(xiàn)程以-XX:ThreadStackSize為準(zhǔn)。

?-Xrs
減少JVM對(duì)操作系統(tǒng)信號(hào)(OS Signals)的使用(JDK1.3.1之后才有效),當(dāng)此參數(shù)被設(shè)置之后,jvm將不接收控制臺(tái)的控制handler,以防止與在后臺(tái)以服務(wù)形式運(yùn)行的JVM沖突(這個(gè)用的比較少,參考:http://www.blogjava.net/midstr/archive/2008/09/21/230265.html)。

-Xprof
?跟蹤正運(yùn)行的程序,并將跟蹤數(shù)據(jù)在標(biāo)準(zhǔn)輸出輸出;適合于開(kāi)發(fā)環(huán)境調(diào)試。

-Xnoclassgc
?關(guān)閉針對(duì)class的gc功能;因?yàn)槠渥柚箖?nèi)存回收,所以可能會(huì)導(dǎo)致OutOfMemoryError錯(cuò)誤,慎用;

-Xincgc
?開(kāi)啟增量gc(默認(rèn)為關(guān)閉);這有助于減少長(zhǎng)時(shí)間GC時(shí)應(yīng)用程序出現(xiàn)的停頓;但由于可能和應(yīng)用程序并發(fā)執(zhí)行,所以會(huì)降低CPU對(duì)應(yīng)用的處理能力。

-Xloggc:file
?與-verbose:gc功能類(lèi)似,只是將每次GC事件的相關(guān)情況記錄到一個(gè)文件中,文件的位置最好在本地,以避免網(wǎng)絡(luò)的潛在問(wèn)題。
?若與verbose命令同時(shí)出現(xiàn)在命令行中,則以-Xloggc為準(zhǔn)。

非Stable參數(shù)(非靜態(tài)參數(shù))
以-XX表示的非Stable參數(shù),雖然在官方文檔中是不確定的,不健壯的,各個(gè)公司的實(shí)現(xiàn)也各有不同,但往往非常實(shí)用,所以這部分參數(shù)對(duì)于GC非常重要。JVM(Hotspot)中主要的參數(shù)可以大致分為3類(lèi)(參考http://blog.csdn.net/sfdev/article/details/2063928):

  • 性能參數(shù)( Performance Options):用于JVM的性能調(diào)優(yōu)和內(nèi)存分配控制,如初始化內(nèi)存大小的設(shè)置;
  • 行為參數(shù)(Behavioral Options):用于改變JVM的基礎(chǔ)行為,如GC的方式和算法的選擇;
  • 調(diào)試參數(shù)(Debugging Options):用于監(jiān)控、打印、輸出等jvm參數(shù),用于顯示jvm更加詳細(xì)的信息;

比較詳細(xì)的非Stable參數(shù)總結(jié),請(qǐng)參考Java 6 JVM參數(shù)選項(xiàng)大全(中文版),
對(duì)于非Stable參數(shù),使用方法有4種:

  • -XX:+<option> 啟用選項(xiàng)
  • -XX:-<option> 不啟用選項(xiàng)
  • -XX:<option>=<number> 給選項(xiàng)設(shè)置一個(gè)數(shù)字類(lèi)型值,可跟單位,例如 32k, 1024m, 2g
  • -XX:<option>=<string> 給選項(xiàng)設(shè)置一個(gè)字符串值,例如-XX:HeapDumpPath=./dump.core

首先介紹性能參數(shù),性能參數(shù)往往用來(lái)定義內(nèi)存分配的大小和比例,相比于行為參數(shù)和調(diào)試參數(shù),一個(gè)比較明顯的區(qū)別是性能參數(shù)后面往往跟的有數(shù)值,常用如下:

參數(shù)及其默認(rèn)值描述
-XX:NewSize=2.125m 新生代對(duì)象生成時(shí)占用內(nèi)存的默認(rèn)值
-XX:MaxNewSize=size新生成對(duì)象能占用內(nèi)存的最大值
-XX:MaxPermSize=64m方法區(qū)所能占用的最大內(nèi)存(非堆內(nèi)存)
-XX:PermSize=64m方法區(qū)分配的初始內(nèi)存
-XX:MaxTenuringThreshold=15 對(duì)象在新生代存活區(qū)切換的次數(shù)(堅(jiān)持過(guò)MinorGC的次數(shù),每堅(jiān)持過(guò)一次,該值就增加1),大于該值會(huì)進(jìn)入老年代
-XX:MaxHeapFreeRatio=70 GC后java堆中空閑量占的最大比例,大于該值,則堆內(nèi)存會(huì)減少
-XX:MinHeapFreeRatio=40GC后java堆中空閑量占的最小比例,小于該值,則堆內(nèi)存會(huì)增加
-XX:NewRatio=2新生代內(nèi)存容量與老生代內(nèi)存容量的比例
-XX:ReservedCodeCacheSize= 32m保留代碼占用的內(nèi)存容量
-XX:ThreadStackSize=512設(shè)置線(xiàn)程棧大小,若為0則使用系統(tǒng)默認(rèn)值
-XX:LargePageSizeInBytes=4m 設(shè)置用于Java堆的大頁(yè)面尺寸
-XX:PretenureSizeThreshold= size ??大于該值的對(duì)象直接晉升入老年代(這種對(duì)象少用為好)
-XX:SurvivorRatio=8Eden區(qū)域Survivor區(qū)的容量比值,如默認(rèn)值為8,代表Eden:Survivor1:Survivor2=8:1:1

常用的行為參數(shù),主要用來(lái)選擇使用什么樣的垃圾收集器組合,以及控制運(yùn)行過(guò)程中的GC策略等:

參數(shù)及其默認(rèn)值描述
-XX:-UseSerialGC 啟用串行GC,即采用Serial+Serial Old模式
-XX:-UseParallelGC 啟用并行GC,即采用Parallel Scavenge+Serial Old收集器組合(-Server模式下的默認(rèn)組合)
-XX:GCTimeRatio=99設(shè)置用戶(hù)執(zhí)行時(shí)間占總時(shí)間的比例(默認(rèn)值99,即1%的時(shí)間用于GC)
-XX:MaxGCPauseMillis=time設(shè)置GC的最大停頓時(shí)間(這個(gè)參數(shù)只對(duì)Parallel Scavenge有效)
-XX:+UseParNewGC使用ParNew+Serial Old收集器組合
-XX:ParallelGCThreads設(shè)置執(zhí)行內(nèi)存回收的線(xiàn)程數(shù),在+UseParNewGC的情況下使用
-XX:+UseParallelOldGC 使用Parallel Scavenge +Parallel Old組合收集器
-XX:+UseConcMarkSweepGC使用ParNew+CMS+Serial Old組合并發(fā)收集,優(yōu)先使用ParNew+CMS,當(dāng)用戶(hù)線(xiàn)程內(nèi)存不足時(shí),采用備用方案Serial Old收集。
-XX:-DisableExplicitGC禁止調(diào)用System.gc();但jvm的gc仍然有效
-XX:+ScavengeBeforeFullGC新生代GC優(yōu)先于Full GC執(zhí)行

常用的調(diào)試參數(shù),主要用于監(jiān)控和打印GC的信息:

參數(shù)及其默認(rèn)值描述
-XX:-CITime打印消耗在JIT編譯的時(shí)間
-XX:ErrorFile=./hs_err_pid<pid>.log保存錯(cuò)誤日志或者數(shù)據(jù)到文件中
-XX:-ExtendedDTraceProbes開(kāi)啟solaris特有的dtrace探針
-XX:HeapDumpPath=./java_pid<pid>.hprof指定導(dǎo)出堆信息時(shí)的路徑或文件名
-XX:-HeapDumpOnOutOfMemoryError當(dāng)首次遭遇OOM時(shí)導(dǎo)出此時(shí)堆中相關(guān)信息
-XX:OnError="<cmd args>;<cmd args>"出現(xiàn)致命ERROR之后運(yùn)行自定義命令
-XX:OnOutOfMemoryError="<cmd args>;<cmd args>"當(dāng)首次遭遇OOM時(shí)執(zhí)行自定義命令
-XX:-PrintClassHistogram遇到Ctrl-Break后打印類(lèi)實(shí)例的柱狀信息,與jmap -histo功能相同
-XX:-PrintConcurrentLocks遇到Ctrl-Break后打印并發(fā)鎖的相關(guān)信息,與jstack -l功能相同
-XX:-PrintCommandLineFlags打印在命令行中出現(xiàn)過(guò)的標(biāo)記
-XX:-PrintCompilation當(dāng)一個(gè)方法被編譯時(shí)打印相關(guān)信息
-XX:-PrintGC每次GC時(shí)打印相關(guān)信息
-XX:-PrintGC Details每次GC時(shí)打印詳細(xì)信息
-XX:-PrintGCTimeStamps打印每次GC的時(shí)間戳
-XX:-TraceClassLoading跟蹤類(lèi)的加載信息
-XX:-TraceClassLoadingPreorder跟蹤被引用到的所有類(lèi)的加載信息
-XX:-TraceClassResolution跟蹤常量池
-XX:-TraceClassUnloading跟蹤類(lèi)的卸載信息
-XX:-TraceLoaderConstraints跟蹤類(lèi)加載器約束的相關(guān)信息

?再次聲明,上面的三種參數(shù),主要參考了博客:http://blog.csdn.net/sfdev/article/details/2063928和http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm,后一個(gè)比較全面,有興趣的可以仔細(xì)研讀。
這些參數(shù)將為我們進(jìn)行GC的監(jiān)控與調(diào)優(yōu)提供很大助力,是我們進(jìn)行GC相關(guān)操作的重要工具。
收集器搭配


在介紹了常用的配置參數(shù)之后,我們將開(kāi)始真正的JVM實(shí)操征程,首先,我們要為應(yīng)用程序選擇一個(gè)合適的垃圾收集器組合,本節(jié)請(qǐng)參考《Java系列筆記(3) - Java 內(nèi)存區(qū)域和GC機(jī)制》一文中的“垃圾收集器”一節(jié),及上節(jié)中的行為參數(shù)。

這里需要再次引用這幅圖(圖來(lái)源于《深入理解Java虛擬機(jī):JVM高級(jí)特效與最佳實(shí)現(xiàn)》,圖中兩個(gè)收集器之間有連線(xiàn),說(shuō)明它們可以配合使用):


Serial收集器:?Serial收集器是在client模式下默認(rèn)的新生代收集器,其收集效率大約是100M左右的內(nèi)存需要幾十到100多毫秒;在client模式下,收集桌面應(yīng)用的內(nèi)存垃圾,基本上不影響用戶(hù)體驗(yàn)。所以,一般的Java桌面應(yīng)用中,直接使用Serial收集器(不需要配置參數(shù),用默認(rèn)即可)。
ParNew收集器:Serial收集器的多線(xiàn)程版本,這種收集器默認(rèn)開(kāi)通的線(xiàn)程數(shù)與CPU數(shù)量相同,-XX:ParallelGCThreads可以用來(lái)設(shè)置開(kāi)通的線(xiàn)程數(shù)。
可以與CMS收集器配合使用,事實(shí)上用-XX:+UseConcMarkSweepGC選擇使用CMS收集器時(shí),默認(rèn)使用的就是ParNew收集器,所以不需要額外設(shè)置-XX:+UseParNewGC,設(shè)置了也不會(huì)沖突,因?yàn)闀?huì)將ParNew+Serial Old作為一個(gè)備選方案;
如果單獨(dú)使用-XX:+UseParNewGC參數(shù),則選擇的是ParNew+Serial Old收集器組合收集器。
一般情況下,在server模式下,如果選擇CMS收集器,則優(yōu)先選擇ParNew收集器。
Parallel Scavenge收集器:關(guān)注的是吞吐量(關(guān)于吞吐量的含義見(jiàn)上一篇博客),可以這么理解,關(guān)注吞吐量,意味著強(qiáng)調(diào)任務(wù)更快的完成,而如CMS等關(guān)注停頓時(shí)間短的收集器,強(qiáng)調(diào)的是用戶(hù)交互體驗(yàn)。
在需要關(guān)注吞吐量的場(chǎng)合,比如數(shù)據(jù)運(yùn)算服務(wù)器等,就可以使用Parallel Scavenge收集器。

老年代收集器如下:
Serial Old收集器:在1.5版本及以前可以與 Parallel Scavenge結(jié)合使用(事實(shí)上,也是當(dāng)時(shí)Parallel Scavenge唯一能用的版本),另外就是在使用CMS收集器時(shí)的備用方案,發(fā)生 Concurrent Mode Failure時(shí)使用。
如果是單獨(dú)使用,Serial Old一般用在client模式中。
Parallel Old收集器:在1.6版本之后,與 Parallel Scavenge結(jié)合使用,以更好的貫徹吞吐量?jī)?yōu)先的思想,如果是關(guān)注吞吐量的服務(wù)器,建議使用Parallel Scavenge + Parallel Old 收集器。
CMS收集器:這是當(dāng)前階段使用很廣的一種收集器,國(guó)內(nèi)很多大的互聯(lián)網(wǎng)公司線(xiàn)上服務(wù)器都使用這種垃圾收集器(http://blog.csdn.net/wisgood/article/details/17067203),筆者公司的收集器也是這種,CMS收集器以獲取最短回收停頓時(shí)間為目標(biāo),非常適合對(duì)用戶(hù)響應(yīng)比較高的B/S架構(gòu)服務(wù)器。
?CMSIncrementalMode:?CMS收集器變種,屬增量式垃圾收集器,在并發(fā)標(biāo)記和并發(fā)清理時(shí)交替運(yùn)行垃圾收集器和用戶(hù)線(xiàn)程。
?G1 收集器:面向服務(wù)器端應(yīng)用的垃圾收集器,計(jì)劃未來(lái)替代CMS收集器。

  • 一般來(lái)說(shuō),如果是Java桌面應(yīng)用,建議采用Serial+Serial Old收集器組合,即:-XX:+UseSerialGC(-client下的默認(rèn)參數(shù))
  • 在開(kāi)發(fā)/測(cè)試環(huán)境,可以采用默認(rèn)參數(shù),即采用Parallel Scavenge+Serial Old收集器組合,即:-XX:+UseParallelGC(-server下的默認(rèn)參數(shù))
  • 在線(xiàn)上運(yùn)算優(yōu)先的環(huán)境,建議采用Parallel Scavenge+Serial Old收集器組合,即:-XX:+UseParallelGC
  • 在線(xiàn)上服務(wù)響應(yīng)優(yōu)先的環(huán)境,建議采用ParNew+CMS+Serial Old收集器組合,即:-XX:+UseConcMarkSweepGC

另外在選擇了垃圾收集器組合之后,還要配置一些輔助參數(shù),以保證收集器可以更好的工作。關(guān)于這些參數(shù),請(qǐng)?jiān)趆ttp://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm中查詢(xún)其意義和用法,如:

  • 選用了ParNew收集器,你可能需要配置4個(gè)參數(shù): -XX:SurvivorRatio, -XX:PretenureSizeThreshold, -XX:+HandlePromotionFailure,-XX:MaxTenuringThreshold;
  • 選用了 Parallel Scavenge收集器,你可能需要配置3個(gè)參數(shù): -XX:MaxGCPauseMillis,-XX:GCTimeRatio, -XX:+UseAdaptiveSizePolicy ;
  • 選用了CMS收集器,你可能需要配置3個(gè)參數(shù): -XX:CMSInitiatingOccupancyFraction, -XX:+UseCMSCompactAtFullCollection, -XX:CMSFullGCsBeforeCompaction;

啟動(dòng)內(nèi)存分配


關(guān)于GC有一個(gè)常見(jiàn)的疑問(wèn)是,在啟動(dòng)時(shí),我的內(nèi)存如何分配?經(jīng)過(guò)前面的學(xué)習(xí),已經(jīng)很容易知道,用-Xmn,-Xmx,-Xms,-Xss,-XX:NewSize,-XX:MaxNewSize,-XX:MaxPermSize,-XX:PermSize,-XX:SurvivorRatio,-XX:PretenureSizeThreshold,-XX:MaxTenuringThreshold就基本可以配置內(nèi)存啟動(dòng)時(shí)的分配情況。但是,具體配置多少?設(shè)置小了,頻繁GC(甚至內(nèi)存溢出),設(shè)置大了,內(nèi)存浪費(fèi)。結(jié)合前面對(duì)于內(nèi)存區(qū)域和其作用的學(xué)習(xí),盡量考慮如下建議:

  • -XX:PermSize盡量比-XX:MaxPermSize小,-XX:MaxPermSize>= 2 * -XX:PermSize, -XX:PermSize> 64m,一般對(duì)于4G內(nèi)存的機(jī)器,-XX:MaxPermSize不會(huì)超過(guò)256m;
  • -Xms =? -Xmx(線(xiàn)上Server模式),以防止抖動(dòng),大小受操作系統(tǒng)和內(nèi)存大小限制,如果是32位系統(tǒng),則一般-Xms設(shè)置為1g-2g(假設(shè)有4g內(nèi)存),在64位系統(tǒng)上,沒(méi)有限制,不過(guò)一般為機(jī)器最大內(nèi)存的一半左右;
  • -Xmn,在開(kāi)發(fā)環(huán)境下,可以用-XX:NewSize和-XX:MaxNewSize來(lái)設(shè)置新生代的大小(-XX:NewSize<=-XX:MaxNewSize),在生產(chǎn)環(huán)境,建議只設(shè)置-Xmn,一般-Xmn的大小是-Xms的1/2左右,不要設(shè)置的過(guò)大或過(guò)小,過(guò)大導(dǎo)致老年代變小,頻繁Full GC,過(guò)小導(dǎo)致minor GC頻繁。如果不設(shè)置-Xmn,可以采用-XX:NewRatio=2來(lái)設(shè)置,也是一樣的效果;
  • -Xss一般是不需要改的,默認(rèn)值即可。
  • -XX:SurvivorRatio一般設(shè)置8-10左右,推薦設(shè)置為10,也即:Survivor區(qū)的大小是Eden區(qū)的1/10,一般來(lái)說(shuō),普通的Java程序應(yīng)用,一次minorGC后,至少98%-99%的對(duì)象,都會(huì)消亡,所以,survivor區(qū)設(shè)置為Eden區(qū)的1/10左右,能使Survivor區(qū)容納下10-20次的minor GC才滿(mǎn),然后再進(jìn)入老年代,這個(gè)與 -XX:MaxTenuringThreshold的默認(rèn)值15次也相匹配的。如果XX:SurvivorRatio設(shè)置的太小,會(huì)導(dǎo)致本來(lái)能通過(guò)minor回收掉的對(duì)象提前進(jìn)入老年代,產(chǎn)生不必要的full gc;如果XX:SurvivorRatio設(shè)置的太大,會(huì)導(dǎo)致Eden區(qū)相應(yīng)的被壓縮。
  • -XX:MaxTenuringThreshold默認(rèn)為15,也就是說(shuō),經(jīng)過(guò)15次Survivor輪換(即15次minor GC),就進(jìn)入老年代, 如果設(shè)置的小的話(huà),則年輕代對(duì)象在survivor中存活的時(shí)間減小,提前進(jìn)入年老代,對(duì)于年老代比較多的應(yīng)用,可以提高效率。如果將此值設(shè)置為一個(gè)較大值,則年輕代對(duì)象會(huì)在Survivor區(qū)進(jìn)行多次復(fù)制,這樣可以增加對(duì)象在年輕代的存活時(shí)間,增加在年輕代即被回收的概率。需要注意的是,設(shè)置了 -XX:MaxTenuringThreshold,并不代表著,對(duì)象一定在年輕代存活15次才被晉升進(jìn)入老年代,它只是一個(gè)最大值,事實(shí)上,存在一個(gè)動(dòng)態(tài)計(jì)算機(jī)制,計(jì)算每次晉入老年代的閾值,取閾值和MaxTenuringThreshold中較小的一個(gè)為準(zhǔn)。
  • -XX:PretenureSizeThreshold一般采用默認(rèn)值即可。
  • 監(jiān)控工具和方法


    在JVM運(yùn)行的過(guò)程中,為保證其穩(wěn)定、高效,或在出現(xiàn)GC問(wèn)題時(shí)分析問(wèn)題原因,我們需要對(duì)GC進(jìn)行監(jiān)控。所謂監(jiān)控,其實(shí)就是分析清楚當(dāng)前GC的情況。其目的是鑒別JVM是否在高效的進(jìn)行垃圾回收,以及有沒(méi)有必要進(jìn)行調(diào)優(yōu)。
    通過(guò)監(jiān)控GC,我們可以搞清楚很多問(wèn)題,如:
    1,minor GC和full GC的頻率;
    2,執(zhí)行一次GC所消耗的時(shí)間;
    3,新生代的對(duì)象何時(shí)被移到老生代以及花費(fèi)了多少時(shí)間;
    4,每次GC中,其它線(xiàn)程暫停(Stop the world)的時(shí)間;
    5,每次GC的效果如何,是否不理想;
    ………………
    監(jiān)控GC的工具分為2種:命令行工具和圖形工具;
    常用的命令行工具有:
    注:下面的命令都在JAVA_HOME/bin中,是java自帶的命令。如果您發(fā)現(xiàn)無(wú)法使用,請(qǐng)直接進(jìn)入Java安裝目錄調(diào)用或者先設(shè)置Java的環(huán)境變量,一個(gè)簡(jiǎn)單的辦法為:直接運(yùn)行命令 export PATH=$JAVA_HOME/bin:$PATH;另外,一般的,在Linux下,下面的命令需要sudo權(quán)限,在windows下,部分命令的部分選項(xiàng)不能使用。
    1,jps
    jps命令用于查詢(xún)正在運(yùn)行的JVM進(jìn)程,常用的參數(shù)為:
    ??? -q:只輸出LVMID,省略主類(lèi)的名稱(chēng)
    ??? -m:輸出虛擬機(jī)進(jìn)程啟動(dòng)時(shí)傳給主類(lèi)main()函數(shù)的參數(shù)
    ??? -l:輸出主類(lèi)的全類(lèi)名,如果進(jìn)程執(zhí)行的是Jar包,輸出Jar路徑
    ??? -v:輸出虛擬機(jī)進(jìn)程啟動(dòng)時(shí)JVM參數(shù)
    命令格式:jps [option] [hostid]?
    一個(gè)簡(jiǎn)單的例子:


    在上圖中,有一個(gè)vid為309的apache進(jìn)程在提供web服務(wù)。

    2,jstat
    jstat可以實(shí)時(shí)顯示本地或遠(yuǎn)程JVM進(jìn)程中類(lèi)裝載、內(nèi)存、垃圾收集、JIT編譯等數(shù)據(jù)(如果要顯示遠(yuǎn)程JVM信息,需要遠(yuǎn)程主機(jī)開(kāi)啟RMI支持)。如果在服務(wù)啟動(dòng)時(shí)沒(méi)有指定啟動(dòng)參數(shù)-verbose:gc,則可以用jstat實(shí)時(shí)查看gc情況。
    jstat有如下選項(xiàng):
    ?? -class:監(jiān)視類(lèi)裝載、卸載數(shù)量、總空間及類(lèi)裝載所耗費(fèi)的時(shí)間
    ?? -gc:監(jiān)聽(tīng)Java堆狀況,包括Eden區(qū)、兩個(gè)Survivor區(qū)、老年代、永久代等的容量,以用空間、GC時(shí)間合計(jì)等信息
    ?? -gccapacity:監(jiān)視內(nèi)容與-gc基本相同,但輸出主要關(guān)注java堆各個(gè)區(qū)域使用到的最大和最小空間
    ?? -gcutil:監(jiān)視內(nèi)容與-gc基本相同,但輸出主要關(guān)注已使用空間占總空間的百分比
    ?? -gccause:與-gcutil功能一樣,但是會(huì)額外輸出導(dǎo)致上一次GC產(chǎn)生的原因
    ?? -gcnew:監(jiān)視新生代GC狀況
    ?? -gcnewcapacity:監(jiān)視內(nèi)同與-gcnew基本相同,輸出主要關(guān)注使用到的最大和最小空間
    ?? -gcold:監(jiān)視老年代GC情況
    ?? -gcoldcapacity:監(jiān)視內(nèi)同與-gcold基本相同,輸出主要關(guān)注使用到的最大和最小空間
    ?? -gcpermcapacity:輸出永久代使用到最大和最小空間
    ?? -compiler:輸出JIT編譯器編譯過(guò)的方法、耗時(shí)等信息
    ?? -printcompilation:輸出已經(jīng)被JIT編譯的方法
    命令格式:jstat [option vmid [interval[s|ms] [count]]]
    jstat可以監(jiān)控遠(yuǎn)程機(jī)器,命令格式中VMID和LVMID特別說(shuō)明:如果是本地虛擬機(jī)進(jìn)程,VMID和LVMID是一致的,如果是遠(yuǎn)程虛擬機(jī)進(jìn)程,那么VMID格式是: [protocol:][//]lvmid[@hostname[:port]/servername],如果省略interval和count,則只查詢(xún)一次
    查看gc情況的例子:


    在圖中,命令sudo jstat -gc 309 1000 5代表著:搜集vid為309的java進(jìn)程的整體gc狀態(tài), 每1000ms收集一次,共收集5次;XXXC表示該區(qū)容量,XXXU表示該區(qū)使用量,各列解釋如下:
    S0C:S0區(qū)容量(S1區(qū)相同,略)
    S0U:S0區(qū)已使用
    EC:E區(qū)容量
    EU:E區(qū)已使用
    OC:老年代容量
    OU:老年代已使用
    PC:Perm容量
    PU:Perm區(qū)已使用
    YGC:Young GC(Minor GC)次數(shù)
    YGCT:Young GC總耗時(shí)
    FGC:Full GC次數(shù)
    FGCT:Full GC總耗時(shí)
    GCT:GC總耗時(shí)

    用gcutil查看內(nèi)存的例子:


    圖中的各列與用gc參數(shù)時(shí)基本一致,不同的是這里顯示的是已占用的百分比,如S0為86.53,代表著S0區(qū)已使用了86.53%

    3,jinfo
    用于查詢(xún)當(dāng)前運(yùn)行這的JVM屬性和參數(shù)的值。
    jinfo可以使用如下選項(xiàng):
    ?? -flag:顯示未被顯示指定的參數(shù)的系統(tǒng)默認(rèn)值
    ?? -flag [+|-]name或-flag name=value: 修改部分參數(shù)
    ?? -sysprops:打印虛擬機(jī)進(jìn)程的System.getProperties()
    ?命令格式:jinfo [option] pid?

    4,jmap
    用于顯示當(dāng)前Java堆和永久代的詳細(xì)信息(如當(dāng)前使用的收集器,當(dāng)前的空間使用率等)
    ?? -dump:生成java堆轉(zhuǎn)儲(chǔ)快照
    ?? -heap:顯示java堆詳細(xì)信息(只在Linux/Solaris下有效)
    ?? -F:當(dāng)虛擬機(jī)進(jìn)程對(duì)-dump選項(xiàng)沒(méi)有響應(yīng)時(shí),可使用這個(gè)選項(xiàng)強(qiáng)制生成dump快照(只在Linux/Solaris下有效)
    ?? -finalizerinfo:顯示在F-Queue中等待Finalizer線(xiàn)程執(zhí)行finalize方法的對(duì)象(只在Linux/Solaris下有效)
    ?? -histo:顯示堆中對(duì)象統(tǒng)計(jì)信息
    ?? -permstat:以ClassLoader為統(tǒng)計(jì)口徑顯示永久代內(nèi)存狀態(tài)(只在Linux/Solaris下有效)
    ?命令格式:jmap [option] vmid
    其中前面3個(gè)參數(shù)最重要,如:
    查看對(duì)詳細(xì)信息:sudo jmap -heap 309
    生成dump文件: sudo jmap -dump:file=./test.prof 309
    部分用戶(hù)沒(méi)有權(quán)限時(shí),采用admin用戶(hù):sudo -u admin -H? jmap -dump:format=b,file=文件名.hprof pid
    查看當(dāng)前堆中對(duì)象統(tǒng)計(jì)信息:sudo? jmap -histo 309:該命令顯示3列,分別為對(duì)象數(shù)量,對(duì)象大小,對(duì)象名稱(chēng),通過(guò)該命令可以查看是否內(nèi)存中有大對(duì)象;
    有的用戶(hù)可能沒(méi)有jmap權(quán)限:sudo -u admin -H jmap -histo 309 | less

    5,jhat
    用于分析使用jmap生成的dump文件,是JDK自帶的工具,使用方法為: jhat -J -Xmx512m [file]
    不過(guò)jhat沒(méi)有mat好用,推薦使用mat(Eclipse插件: http://www.eclipse.org/mat ),mat速度更快,而且是圖形界面。

    6,jstack
    用于生成當(dāng)前JVM的所有線(xiàn)程快照,線(xiàn)程快照是虛擬機(jī)每一條線(xiàn)程正在執(zhí)行的方法,目的是定位線(xiàn)程出現(xiàn)長(zhǎng)時(shí)間停頓的原因。
    ?? -F:當(dāng)正常輸出的請(qǐng)求不被響應(yīng)時(shí),強(qiáng)制輸出線(xiàn)程堆棧
    ?? -l:除堆棧外,顯示關(guān)于鎖的附加信息
    ?? -m:如果調(diào)用到本地方法的話(huà),可以顯示C/C++的堆棧
    命令格式:jstack [option] vmid


    7,-verbosegc
    -verbosegc是一個(gè)比較重要的啟動(dòng)參數(shù),記錄每次gc的日志,下面的表格對(duì)比了jstat和-verbosegc:


    jstat
    -verbosegc
    監(jiān)控對(duì)象 運(yùn)行在本機(jī)的Java應(yīng)用可以把日志輸出到終端上,或者借助jstatd命令通過(guò)網(wǎng)絡(luò)連接遠(yuǎn)程的Java應(yīng)用。 只有那些把-verbogc作為啟動(dòng)參數(shù)的JVM。
    輸出信息 堆狀態(tài)(已用空間,最大限制,GC執(zhí)行次數(shù)/時(shí)間,等等) 執(zhí)行GC前后新生代和老年代空間大小,GC執(zhí)行時(shí)間。
    輸出時(shí)間 Every designated time
    每次設(shè)定好的時(shí)間。
    每次GC發(fā)生的時(shí)候。
    用途 觀(guān)察堆空間變化情況 了解單次GC產(chǎn)生的效果。


    與-verbosegc配合使用的一些常用參數(shù)為:
    ?? -XX:+PrintGCDetails,打印GC信息,這是-verbosegc默認(rèn)開(kāi)啟的選項(xiàng)
    ?? -XX:+PrintGCTimeStamps,打印每次GC的時(shí)間戳
    ?? -XX:+PrintHeapAtGC:每次GC時(shí),打印堆信息
    ?? -XX:+PrintGCDateStamps (from JDK 6 update 4) :打印GC日期,適合于長(zhǎng)期運(yùn)行的服務(wù)器
    ?? -Xloggc:/home/admin/logs/gc.log:制定打印信息的記錄的日志位置
    每條verbosegc打印出的gc日志,都類(lèi)似于下面的格式:
    time [GC [<collector>: <starting occupancy1> -> <ending occupancy1>(total occupancy1), <pause time1> secs] <starting occupancy3> -> <ending occupancy3>(total occupancy3), <pause time3> secs]?
    如:


    這些選項(xiàng)的意義是:
    time:執(zhí)行GC的時(shí)間,需要添加-XX:+PrintGCDateStamps參數(shù)才有;
    collector:minor gc使用的收集器的名字。
    starting occupancy1:GC執(zhí)行前新生代空間大小。
    ending occupancy1:GC執(zhí)行后新生代空間大小。
    total occupancy1:新生代總大小
    pause time1:因?yàn)閳?zhí)行minor GC,Java應(yīng)用暫停的時(shí)間。
    starting occupancy3:GC執(zhí)行前堆區(qū)域總大小
    ending occupancy3:GC執(zhí)行后堆區(qū)域總大小
    total occupancy3:堆區(qū)總大小
    pause time3:Java應(yīng)用由于執(zhí)行堆空間GC(包括full GC)而停止的時(shí)間。

    8,可視化工具
    監(jiān)控和分析GC也有一些可視化工具,比較常見(jiàn)的有JConsole和VisualVM,有興趣的可以看看下面的文章,在此不再贅述:
    http://blog.csdn.net/java2000_wl/article/details/8049707

    調(diào)優(yōu)方法


    一切都是為了這一步,調(diào)優(yōu),在調(diào)優(yōu)之前,我們需要記住下面的原則:

  • 多數(shù)的Java應(yīng)用不需要在服務(wù)器上進(jìn)行GC優(yōu)化;
  • 多數(shù)導(dǎo)致GC問(wèn)題的Java應(yīng)用,都不是因?yàn)槲覀儏?shù)設(shè)置錯(cuò)誤,而是代碼問(wèn)題;
  • 在應(yīng)用上線(xiàn)之前,先考慮將機(jī)器的JVM參數(shù)設(shè)置到最優(yōu)(最適合);
  • 減少創(chuàng)建對(duì)象的數(shù)量;
  • 減少使用全局變量和大對(duì)象;
  • GC優(yōu)化是到最后不得已才采用的手段;
  • 在實(shí)際使用中,分析GC情況優(yōu)化代碼比優(yōu)化GC參數(shù)要多得多;
  • GC優(yōu)化的目的有兩個(gè)(http://www.360doc.com/content/13/0305/10/15643_269388816.shtml):

    • 將轉(zhuǎn)移到老年代的對(duì)象數(shù)量降低到最小;
    • 減少full GC的執(zhí)行時(shí)間;

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

    • 減少使用全局變量和大對(duì)象;
    • 調(diào)整新生代的大小到最合適;
    • 設(shè)置老年代的大小為最合適;
    • 選擇合適的GC收集器;

    在上面的4條方法中,用了幾個(gè)“合適”,那究竟什么才算合適,一般的,請(qǐng)參考上面“收集器搭配”和“啟動(dòng)內(nèi)存分配”兩節(jié)中的建議。但這些建議不是萬(wàn)能的,需要根據(jù)您的機(jī)器和應(yīng)用情況進(jìn)行發(fā)展和變化,實(shí)際操作中,可以將兩臺(tái)機(jī)器分別設(shè)置成不同的GC參數(shù),并且進(jìn)行對(duì)比,選用那些確實(shí)提高了性能或減少了GC時(shí)間的參數(shù)。

    真正熟練的使用GC調(diào)優(yōu),是建立在多次進(jìn)行GC監(jiān)控和調(diào)優(yōu)的實(shí)戰(zhàn)經(jīng)驗(yàn)上的,進(jìn)行監(jiān)控和調(diào)優(yōu)的一般步驟為:
    1,監(jiān)控GC的狀態(tài)
    使用各種JVM工具,查看當(dāng)前日志,分析當(dāng)前JVM參數(shù)設(shè)置,并且分析當(dāng)前堆內(nèi)存快照和gc日志,根據(jù)實(shí)際的各區(qū)域內(nèi)存劃分和GC執(zhí)行時(shí)間,覺(jué)得是否進(jìn)行優(yōu)化;
    2,分析結(jié)果,判斷是否需要優(yōu)化
    如果各項(xiàng)參數(shù)設(shè)置合理,系統(tǒng)沒(méi)有超時(shí)日志出現(xiàn),GC頻率不高,GC耗時(shí)不高,那么沒(méi)有必要進(jìn)行GC優(yōu)化;如果GC時(shí)間超過(guò)1-3秒,或者頻繁GC,則必須優(yōu)化;
    注:如果滿(mǎn)足下面的指標(biāo),則一般不需要進(jìn)行GC:

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

    3,調(diào)整GC類(lèi)型和內(nèi)存分配
    如果內(nèi)存分配過(guò)大或過(guò)小,或者采用的GC收集器比較慢,則應(yīng)該優(yōu)先調(diào)整這些參數(shù),并且先找1臺(tái)或幾臺(tái)機(jī)器進(jìn)行beta,然后比較優(yōu)化過(guò)的機(jī)器和沒(méi)有優(yōu)化的機(jī)器的性能對(duì)比,并有針對(duì)性的做出最后選擇;
    4,不斷的分析和調(diào)整
    通過(guò)不斷的試驗(yàn)和試錯(cuò),分析并找到最合適的參數(shù)
    5,全面應(yīng)用參數(shù)
    如果找到了最合適的參數(shù),則將這些參數(shù)應(yīng)用到所有服務(wù)器,并進(jìn)行后續(xù)跟蹤。

    調(diào)優(yōu)實(shí)例


    上面的內(nèi)容都是紙上談兵,下面我們以一些真實(shí)例子來(lái)進(jìn)行說(shuō)明:
    實(shí)例1:
    筆者昨日發(fā)現(xiàn)部分開(kāi)發(fā)測(cè)試機(jī)器出現(xiàn)異常:java.lang.OutOfMemoryError: GC overhead limit exceeded,這個(gè)異常代表:GC為了釋放很小的空間卻耗費(fèi)了太多的時(shí)間,其原因一般有兩個(gè):1,堆太小,2,有死循環(huán)或大對(duì)象;
    筆者首先排除了第2個(gè)原因,因?yàn)檫@個(gè)應(yīng)用同時(shí)是在線(xiàn)上運(yùn)行的,如果有問(wèn)題,早就掛了。所以懷疑是這臺(tái)機(jī)器中堆設(shè)置太小;
    使用ps -ef |grep "java"查看,發(fā)現(xiàn):


    該應(yīng)用的堆區(qū)設(shè)置只有768m,而機(jī)器內(nèi)存有2g,機(jī)器上只跑這一個(gè)java應(yīng)用,沒(méi)有其他需要占用內(nèi)存的地方。另外,這個(gè)應(yīng)用比較大,需要占用的內(nèi)存也比較多;
    筆者通過(guò)上面的情況判斷,只需要改變堆中各區(qū)域的大小設(shè)置即可,于是改成下面的情況:


    跟蹤運(yùn)行情況發(fā)現(xiàn),相關(guān)異常沒(méi)有再出現(xiàn);

    實(shí)例2:(http://www.360doc.com/content/13/0305/10/15643_269388816.shtml)
    一個(gè)服務(wù)系統(tǒng),經(jīng)常出現(xiàn)卡頓,分析原因,發(fā)現(xiàn)Full GC時(shí)間太長(zhǎng):
    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?
    分析上面的數(shù)據(jù),發(fā)現(xiàn)Young GC執(zhí)行了54次,耗時(shí)2.047秒,每次Young GC耗時(shí)37ms,在正常范圍,而Full GC執(zhí)行了5次,耗時(shí)6.946秒,每次平均1.389s,數(shù)據(jù)顯示出來(lái)的問(wèn)題是:Full GC耗時(shí)較長(zhǎng),分析該系統(tǒng)的是指發(fā)現(xiàn),NewRatio=9,也就是說(shuō),新生代和老生代大小之比為1:9,這就是問(wèn)題的原因:
    1,新生代太小,導(dǎo)致對(duì)象提前進(jìn)入老年代,觸發(fā)老年代發(fā)生Full GC;
    2,老年代較大,進(jìn)行Full GC時(shí)耗時(shí)較大;
    優(yōu)化的方法是調(diào)整NewRatio的值,調(diào)整到4,發(fā)現(xiàn)Full GC沒(méi)有再發(fā)生,只有Young GC在執(zhí)行。這就是把對(duì)象控制在新生代就清理掉,沒(méi)有進(jìn)入老年代(這種做法對(duì)一些應(yīng)用是很有用的,但并不是對(duì)所有應(yīng)用都要這么做)

    實(shí)例3:
    一應(yīng)用在性能測(cè)試過(guò)程中,發(fā)現(xiàn)內(nèi)存占用率很高,Full GC頻繁,使用sudo -u admin -H? jmap -dump:format=b,file=文件名.hprof pid 來(lái)dump內(nèi)存,生成dump文件,并使用Eclipse下的mat差距進(jìn)行分析,發(fā)現(xiàn):


    從圖中可以看出,這個(gè)線(xiàn)程存在問(wèn)題,隊(duì)列LinkedBlockingQueue所引用的大量對(duì)象并未釋放,導(dǎo)致整個(gè)線(xiàn)程占用內(nèi)存高達(dá)378m,此時(shí)通知開(kāi)發(fā)人員進(jìn)行代碼優(yōu)化,將相關(guān)對(duì)象釋放掉即可。

    說(shuō)明


    ???? 本文是Java系列筆記的第4篇,這篇文章寫(xiě)了近3個(gè)月,一方面是這部分對(duì)我來(lái)說(shuō)也是學(xué)習(xí)階段,另一方面是這段時(shí)間一直在做項(xiàng)目,直到最近才比較有時(shí)間。
    ???? 本人能力有限,如果有錯(cuò)漏,請(qǐng)留言指正。

    參考資料

    《深入理解Java虛擬機(jī):JVM高級(jí)特效與最佳實(shí)現(xiàn)》
    JVM啟動(dòng)參數(shù)大全, http://www.blogjava.net/midstr/archive/2008/09/21/230265.html
    JVM系列三:JVM參數(shù)設(shè)置、分析, http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
    Java 6 JVM參數(shù)選項(xiàng)大全(中文版), http://kenwublog.com/docs/java6-jvm-options-chinese-edition.htm
    成為JavaGC專(zhuān)家Part II — 如何監(jiān)控Java垃圾回收機(jī)制, http://www.importnew.com/2057.html
    成為Java GC專(zhuān)家系列(3) — 如何優(yōu)化Java垃圾回收機(jī)制, http://www.importnew.com/3146.html
    JDK5.0垃圾收集優(yōu)化之--Don't Pause, http://calvin.iteye.com/blog/91905
    Java HOTSPOT VM參數(shù)大全, http://tech.sina.com.cn/s/2009-09-23/09561077572.shtml
    【原】GC的默認(rèn)方式, http://iamzhongyong.iteye.com/blog/1447314
    JAVA啟動(dòng)參數(shù)大全之三:非Stable參數(shù), http://blog.csdn.net/sfdev/article/details/2063928
    Java虛擬機(jī)學(xué)習(xí) - 內(nèi)存調(diào)優(yōu), http://blog.csdn.net/java2000_wl/article/details/8090940
    內(nèi)存溢出, http://www.open-open.com/home/space.php?uid=71669&do=blog&id=8891
    如何查看JVM的擴(kuò)展參數(shù):-X, http://www.blogjava.net/beansoft/archive/2012/03/01/371088.html
    JVM內(nèi)存狀況查看方法和分析工具, http://hi.baidu.com/kingfly666666/item/e710a4371c60b0f1e7bb7a32
    虛擬機(jī)學(xué)習(xí)系列 - 附 - 虛擬機(jī)參數(shù), http://blog.csdn.net/su1216/article/details/7780924
    ?JVM系列四:生產(chǎn)環(huán)境參數(shù)實(shí)例及分析【生產(chǎn)環(huán)境實(shí)例增加中】, http://www.cnblogs.com/redcreen/archive/2011/05/05/2038331.html
    垃圾收集器與內(nèi)存分配策略, http://raging-sweet.iteye.com/blog/1170198
    JVM垃圾收集器使用調(diào)查:CMS最受歡迎 , http://blog.csdn.net/wisgood/article/details/17067203
    Xms Xmx PermSize MaxPermSize 區(qū)別, http://www.cnblogs.com/mingforyou/archive/2012/03/03/2378143.html
    Java虛擬機(jī)學(xué)習(xí) - JDK可視化監(jiān)控工具, http://blog.csdn.net/java2000_wl/article/details/8049707
    虛擬機(jī)學(xué)習(xí)系列 - 6 - JDK工具, http://blog.csdn.net/su1216/article/details/7780857
    JVM監(jiān)控工具介紹jstack, jconsole, jinfo, jmap, jdb, jstat, http://hi.baidu.com/lotusxyhf/item/9cd8fcb8d6f8c1a5ebba935b
    JVM 與 jstat, http://blog.sina.com.cn/s/blog_56fcfd620100hdcp.html

    轉(zhuǎn)載于:https://www.cnblogs.com/abcd19880817/p/7193876.html

    總結(jié)

    以上是生活随笔為你收集整理的Java系列笔记(4) - JVM监控与调优【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。