The NoteBook of EricKong

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks

          JVM監(jiān)控與調(diào)優(yōu)

          光說不練假把式,學(xué)習(xí)Java GC機(jī)制的目的是為了實(shí)用,也就是為了在JVM出現(xiàn)問題時分析原因并解決之。通過學(xué)習(xí),我覺得JVM監(jiān)控與調(diào)優(yōu)主要的著眼點(diǎn)在于如何配置、如何監(jiān)控、如何優(yōu)化3點(diǎn)上。下面就將針對這3點(diǎn)進(jìn)行學(xué)習(xí)。
               (如果您對Java的內(nèi)存區(qū)域劃分和內(nèi)存回收機(jī)制尚不明確,那在閱讀本文前,請先閱讀我的前一篇博客《Java系列筆記(3) - Java 內(nèi)存區(qū)域和GC機(jī)制》,在該博客中,詳細(xì)敘述了Java HotSpot虛擬機(jī)(Sun/Oracle JDK系列默認(rèn)的虛擬機(jī))的內(nèi)存分配和垃圾回收機(jī)制。本文很多內(nèi)容將依據(jù)上一篇博客,同時,本文所針對的虛擬機(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)程的所有啟動參數(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)都滿足,且不保證向后兼容;
          • 非Stable參數(shù)(-XX),此類參數(shù)各個jvm實(shí)現(xiàn)會有所不同,將來可能會隨時取消,需要慎重使用(但是,這些參數(shù)往往是非常有用的);

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

           
          標(biāo)準(zhǔn)參數(shù)

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

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

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

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

          -classpath / -cp
          JVM加載和搜索文件的目錄路徑,多個路徑用;分隔。注意,如果使用了-classpath,JVM就不會再搜索環(huán)境變量中定義的CLASSPATH路徑。
          JVM搜索路徑的順序?yàn)椋?br style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px" />1,先搜索JVM自帶的jar或zip包(Bootstrat,搜索路徑可以用System.getProperty("sun.boot.class.path")獲得);
          2,搜索JRE_HOME/lib/ext下的jar包(Extension,搜索路徑可以用System.getProperty("java.ext.dirs")獲得);
          3,搜索用戶自定義目錄,順序?yàn)椋寒?dāng)前目錄(.),CLASSPATH,-cp;(搜索路徑用System.getProperty("java.class.path")獲得)

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

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

          非標(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ù)列表(你會發(fā)現(xiàn),其實(shí)并不多哦)。

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


          -Xmn
          新生代內(nèi)存大小的最大值,包括E區(qū)和兩個S區(qū)的總和,使用方法如:-Xmn65535,-Xmn1024k,-Xmn512m,-Xmn1g (-Xms,-Xmx也是種寫法)
          -Xmn只能使用在JDK1.4或之后的版本中,(之前的1.3/1.4版本中,可使用-XX:NewSize設(shè)置年輕代大小,用-XX:MaxNewSize設(shè)置年輕代最大值);
          如果同時設(shè)置了-Xmn和-XX:NewSize,-XX:MaxNewSize,則誰設(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)
          在開發(fā)、測試環(huán)境,可以-XX:NewSize 和 -XX:MaxNewSize來設(shè)置新生代大小,但在線上生產(chǎn)環(huán)境,使用-Xmn一個即可(推薦),或者將-XX:NewSize 和 -XX:MaxNewSize設(shè)置為同一個值,這樣能夠防止在每次GC之后都要調(diào)整堆的大?。矗憾秳?,抖動會嚴(yán)重影響性能)

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

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

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

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

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

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

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

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

          非Stable參數(shù)(非靜態(tài)參數(shù))
          以-XX表示的非Stable參數(shù),雖然在官方文檔中是不確定的,不健壯的,各個公司的實(shí)現(xiàn)也各有不同,但往往非常實(shí)用,所以這部分參數(shù)對于GC非常重要。JVM(Hotspot)中主要的參數(shù)可以大致分為3類(參考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é),請參考Java 6 JVM參數(shù)選項(xiàng)大全(中文版),
          對于非Stable參數(shù),使用方法有4種:

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

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

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

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

          參數(shù)及其默認(rèn)值 描述
          -XX:-UseSerialGC
          啟用串行GC,即采用Serial+Serial Old模式
          -XX:-UseParallelGC
          啟用并行GC,即采用Parallel Scavenge+Serial Old收集器組合(-Server模式下的默認(rèn)組合)
          -XX:GCTimeRatio=99 設(shè)置用戶執(zhí)行時間占總時間的比例(默認(rèn)值99,即1%的時間用于GC)
          -XX:MaxGCPauseMillis=time 設(shè)置GC的最大停頓時間(這個參數(shù)只對Parallel Scavenge有效)
          -XX:+UseParNewGC 使用ParNew+Serial Old收集器組合
          -XX:ParallelGCThreads 設(shè)置執(zhí)行內(nèi)存回收的線程數(shù),在+UseParNewGC的情況下使用
          -XX:+UseParallelOldGC
          使用Parallel Scavenge +Parallel Old組合收集器
          -XX:+UseConcMarkSweepGC 使用ParNew+CMS+Serial Old組合并發(fā)收集,優(yōu)先使用ParNew+CMS,當(dāng)用戶線程內(nèi)存不足時,采用備用方案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編譯的時間
          -XX:ErrorFile=./hs_err_pid<pid>.log 保存錯誤日志或者數(shù)據(jù)到文件中
          -XX:-ExtendedDTraceProbes 開啟solaris特有的dtrace探針
          -XX:HeapDumpPath=./java_pid<pid>.hprof 指定導(dǎo)出堆信息時的路徑或文件名
          -XX:-HeapDumpOnOutOfMemoryError 當(dāng)首次遭遇OOM時導(dǎo)出此時堆中相關(guān)信息
          -XX:OnError="<cmd args>;<cmd args>" 出現(xiàn)致命ERROR之后運(yùn)行自定義命令
          -XX:OnOutOfMemoryError="<cmd args>;<cmd args>" 當(dāng)首次遭遇OOM時執(zhí)行自定義命令
          -XX:-PrintClassHistogram 遇到Ctrl-Break后打印類實(shí)例的柱狀信息,與jmap -histo功能相同
          -XX:-PrintConcurrentLocks 遇到Ctrl-Break后打印并發(fā)鎖的相關(guān)信息,與jstack -l功能相同
          -XX:-PrintCommandLineFlags 打印在命令行中出現(xiàn)過的標(biāo)記
          -XX:-PrintCompilation 當(dāng)一個方法被編譯時打印相關(guān)信息
          -XX:-PrintGC 每次GC時打印相關(guān)信息
          -XX:-PrintGC Details 每次GC時打印詳細(xì)信息
          -XX:-PrintGCTimeStamps 打印每次GC的時間戳
          -XX:-TraceClassLoading 跟蹤類的加載信息
          -XX:-TraceClassLoadingPreorder 跟蹤被引用到的所有類的加載信息
          -XX:-TraceClassResolution 跟蹤常量池
          -XX:-TraceClassUnloading 跟蹤類的卸載信息
          -XX:-TraceLoaderConstraints 跟蹤類加載器約束的相關(guān)信息

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


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

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


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

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

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

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

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

          啟動內(nèi)存分配


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

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

          監(jiān)控工具和方法


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


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

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

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


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

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

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

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


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


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


          與-verbosegc配合使用的一些常用參數(shù)為:
             -XX:+PrintGCDetails,打印GC信息,這是-verbosegc默認(rèn)開啟的選項(xiàng)
             -XX:+PrintGCTimeStamps,打印每次GC的時間戳
             -XX:+PrintHeapAtGC:每次GC時,打印堆信息
             -XX:+PrintGCDateStamps (from JDK 6 update 4) :打印GC日期,適合于長期運(yùn)行的服務(wù)器
             -Xloggc:/home/admin/logs/gc.log:制定打印信息的記錄的日志位置
          每條verbosegc打印出的gc日志,都類似于下面的格式:
          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的時間,需要添加-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)用暫停的時間。
          starting occupancy3:GC執(zhí)行前堆區(qū)域總大小
          ending occupancy3:GC執(zhí)行后堆區(qū)域總大小
          total occupancy3:堆區(qū)總大小
          pause time3:Java應(yīng)用由于執(zhí)行堆空間GC(包括full GC)而停止的時間。

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

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


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

          1. 多數(shù)的Java應(yīng)用不需要在服務(wù)器上進(jìn)行GC優(yōu)化;
          2. 多數(shù)導(dǎo)致GC問題的Java應(yīng)用,都不是因?yàn)槲覀儏?shù)設(shè)置錯誤,而是代碼問題;
          3. 在應(yīng)用上線之前,先考慮將機(jī)器的JVM參數(shù)設(shè)置到最優(yōu)(最適合);
          4. 減少創(chuàng)建對象的數(shù)量;
          5. 減少使用全局變量和大對象;
          6. GC優(yōu)化是到最后不得已才采用的手段;
          7. 在實(shí)際使用中,分析GC情況優(yōu)化代碼比優(yōu)化GC參數(shù)要多得多;

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

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

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

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

          在上面的4條方法中,用了幾個“合適”,那究竟什么才算合適,一般的,請參考上面“收集器搭配”和“啟動內(nèi)存分配”兩節(jié)中的建議。但這些建議不是萬能的,需要根據(jù)您的機(jī)器和應(yīng)用情況進(jìn)行發(fā)展和變化,實(shí)際操作中,可以將兩臺機(jī)器分別設(shè)置成不同的GC參數(shù),并且進(jìn)行對比,選用那些確實(shí)提高了性能或減少了GC時間的參數(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í)行時間,覺得是否進(jìn)行優(yōu)化;
          2,分析結(jié)果,判斷是否需要優(yōu)化
          如果各項(xiàng)參數(shù)設(shè)置合理,系統(tǒng)沒有超時日志出現(xiàn),GC頻率不高,GC耗時不高,那么沒有必要進(jìn)行GC優(yōu)化;如果GC時間超過1-3秒,或者頻繁GC,則必須優(yōu)化;
          注:如果滿足下面的指標(biāo),則一般不需要進(jìn)行GC:

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

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

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


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


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


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

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

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


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

          說明


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


          來源
          http://www.cnblogs.com/zhguang/p/java-jvm-gc.html

          參考資料

          《深入理解Java虛擬機(jī):JVM高級特效與最佳實(shí)現(xiàn)》
          JVM啟動參數(shù)大全, http://www.aygfsteel.com/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專家Part II — 如何監(jiān)控Java垃圾回收機(jī)制, http://www.importnew.com/2057.html
          成為Java GC專家系列(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啟動參數(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.aygfsteel.com/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

          posted on 2015-07-10 09:03 Eric_jiang 閱讀(218) 評論(0)  編輯  收藏 所屬分類: JVM
          主站蜘蛛池模板: 乌什县| 锦屏县| 丽江市| 马龙县| 原阳县| 民县| 黔南| 盐边县| 元江| 瑞昌市| 广丰县| 盐津县| 五家渠市| 安图县| 临朐县| 封丘县| 海伦市| 砀山县| 桐城市| 峡江县| 长乐市| 泊头市| 申扎县| 安西县| 邹平县| 磐石市| 二连浩特市| 江华| 英山县| 上栗县| 离岛区| 黎川县| 宁津县| 林芝县| 福建省| 宜城市| 会宁县| 宁城县| 湘潭县| 屏山县| 宾川县|