JVM內存情況查看方法和分析工具

 

Java自己提供了多種豐富的方法和工具來幫助開發人員查看和分析GC及JVM內存的情況,同時開源界和商業界也有一些工具可用於查看、分析GC及JVM內存的情況。經過這些分析,能夠排查程序中內存泄露的問題及調優程序的性能。下面介紹幾種經常使用的免費工具,其中知名的有JProfiler 等。java

 

  1. 輸出GC日誌linux

 

  輸出GC日誌對於跟蹤分析GC的情況來講,無疑是最直接地分析內存回收情況的方法,只是GC日誌輸出後須要人爲地進行分析,以判斷GC的情況。數據庫

 

  JVM支持將日誌輸出到控制檯或指定的文件中,方法有以下幾種。瀏覽器

 

  輸出到控制檯eclipse

 

  在JVM的啓動參數中加入-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime,按照參數的順序分別輸出GC的簡要信息,GC的詳細信息、GC的時間信息及GC形成的應用暫停的時間。jvm

 

  輸出到指定的文件ide

 

  在1中的jvm啓動參數中再增長-Xloggc: gc.log可指定將gc的信息輸出到gc.log中。工具

 

  可用於GC跟蹤分析的參數還有-verbose:gc、-XX:+PrintTenuringDistribution等。性能

 

  2. GC Portal測試

 

  將GC日誌輸出當然有必定的做用,但若是要靠人爲進行分析,仍是至關複雜的。所以Sun提供了一個GC Portal來幫助分析這些GC日誌,並生成相關的圖形化的報表,GC Portal部署起來會有些麻煩,它須要運行在老版本的Tomcat上,同時須要數據庫,部署完畢後經過上傳日誌文件的方式便可完成GC日誌的分析,此GC日誌輸出的JVM參數爲:-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps [-Xloggc:文件名],在上傳日誌時GC Portal的選項裏只有jdk 1.2或jdk 1.2-1.4的版本。雖然通過測試,JDK 6的日誌也是能夠分析出來的,但它的限制在於僅支持5MB的gc日誌的分析,GC Portal可提供吞吐量的分析、耗費的CPU的時間、形成的應用暫停的時間、每秒重新生代轉化到舊生代的數量、minor GC的情況及Full GC的情況等,如圖1所示。

 

 

圖1  GCPortal示例

 

  GC Portal中還有一個頗有用的部分是提供調整GC參數的預測,例如能夠選擇給young size增長20%的空間。GC Portal會根據當前的日誌信息來評估在調整參數後的運行效果,不必定很準確,但畢竟能帶來一些參考意義。

 

 

 

3. JConsole

 

  JConsole能夠圖形化查看JVM中內存的變化情況,JConsole是JDK 5及以上版本中自帶的工具,位於JDK的bin目錄下,運行時直接運行JConsole.exe或JConsole.sh(要求支持圖形界面)。在本地的Tab頁上看到運行了java的pid,雙擊便可查看相應進程的JVM情況,同時,JConsole也支持查看遠程的JVM的運行情況,具體可參見JConsole的User Guide。

 

  JConsole中顯示了JVM中不少的信息:內存、線程、類和MBean等,在打開JConsole的內存Tab頁後,可看到JVM內存部分的運行情況。這對於分析內存是否有溢出及GC的效果更加直接明瞭,JConsole的運行效果如圖2所示。

 

 

圖2  JConsole運行效果

 

  4. JVisualVM

 

  JVisualVM是JDK 6 update 7以後推出的一個工具,它相似於JProfiler的工具,基於此工具可查看內存的消耗狀況、線程的執行情況及程序中消耗CPU、內存的動做。

 

  在內存分析上,JVisualVM的最大好處是可經過安裝VisualGC插件來分析GC趨勢、內存消耗詳細情況。

 

  VisualGC的運行如圖3所示。

 

 

圖3  VisualGC運行效果

 

  從圖3中可看到各區的內存消耗情況及GC Time的圖表,其提供的Histogram視圖對於調優也有很大幫助。

 

  基於JVisualVM的Profiler中的Memory還可查看對象佔用內存的情況,如圖4所示。

 

4. JMap

 

  JMap是JDK中自帶的一個用於分析JVM內存情況的工具,位於JDK的bin目錄下。使用JMap可查看目前JVM中各個代的內存情況、JVM中對象的內存的佔用情況,以及導出整個JVM中的內存信息。

 

 

圖4  JVisualVM Memory Profiler圖示

 

  查看JVM中各個代的內存情況

 

  在linux上執行jmap -heap [pid],就可查看整個JVM中內存的情況,看到的信息相似以下(和JDK版本、GC策略有關):

 

 

 

using thread-local object allocation.  Parallel GC with 8 thread(s)  Heap Configuration:     MinHeapFreeRatio = 40    MaxHeapFreeRatio = 70    MaxHeapSize      = 1610612736 (1536.0MB)     NewSize          = 524288000 (500.0MB)     MaxNewSize       = 524288000 (500.0MB)     OldSize          = 4194304 (4.0MB)     NewRatio         = 8    SurvivorRatio    = 8    PermSize         = 100663296 (96.0MB)     MaxPermSize      = 268435456 (256.0MB)  Heap Usage:  PS Young Generation  Eden Space:     capacity = 430702592 (410.75MB)     used     = 324439936 (309.4100341796875MB)     free     = 106262656 (101.3399658203125MB)     75.32806675098904% used  From Space:     capacity = 46333952 (44.1875MB)     used     = 13016424 (12.413429260253906MB)     free     = 33317528 (31.774070739746094MB)     28.092626331550566% used  To Space:     capacity = 46792704 (44.625MB)     used     = 0 (0.0MB)     free     = 46792704 (44.625MB)     0.0% used  PS Old Generation     capacity = 1086324736 (1036.0MB)     used     = 945707880 (901.8973159790039MB)     free     = 140616856 (134.1026840209961MB)     87.05572548059884% used  PS Perm Generation     capacity = 100663296 (96.0MB)     used     = 46349592 (44.202415466308594MB)     free     = 54313704 (51.797584533691406MB)     46.044182777404785% used

 

 

從以上信息中可看出JVM堆的配置信息,如NewSize、NewRatio、SurvivorRatio等;JVM堆的使用狀況,新生代中的Eden Space、From Space、To Space的使用狀況,舊生代和持久代的使用狀況。

  要注意的是在使用CMS GC的狀況下,jmap -heap的執行有可能會致使Java進程被掛起。

 

  JVM中對象的內存的佔用狀況

 

  在查看JVM內存情況時,除了要知道每一個代的佔用狀況外,不少時候更要知道其中各個對象佔用的內存大小,這樣便於分析對象的內存佔用狀況,在分析OutOfMemory的場景中尤爲適用。

 

  輸入jmap -histo [pid]便可查看jvm堆中對象的詳細佔用狀況,如圖1所示。

 

 

圖1  jmap -histo運行效果

 

  輸出內容按照佔用空間的大小排序,例如上面的[C,表示char類型的對象在jvm中總共有243 707個實例,佔用了501 638 784 bytes的空間。

 

  導出整個JVM中的內存信息

 

  經過以上方法能查看到JVM中對象內存的佔用狀況,但不少時候還要知道這個對象究竟是誰建立的。例如上面顯示出來的[C,只知道它佔用了那麼多的空間,但不知道是什麼對象建立出的[C,因而jmap提供了導出整個jvm中的內存信息的支持。基於一些jvm內存的分析工具,例如sun JDK 6中的jhat、Eclipse Memory Analyzer,能夠分析jvm中內存的詳細信息,例如[C是哪些對象建立的。

 

  執行以下命令便可導出整個jvm中的內存信息:

 

 

 

jmap -dump:format=b,file=文件名 [pid]

 

 

 

  5. JHat

 

  JHat是Sun JDK 6及以上版本中自帶的一個用於分析jvm堆dump文件的工具,基於此工具可分析jvm heap中對象的內存佔用情況、引用關係等。

 

  執行以下命令分析jvm堆的dump文件:

 

 

 

jhat -J-Xmx1024M [file]

 

 

 

  執行後等待console中輸出Started HTTP server on port 7000,看到後就能夠經過瀏覽器訪問http://ip:7000了,此頁面默認爲按package分類顯示系統中全部的對象實例。在頁面的最下端有Other Queries導航,其中有顯示jvm中對象實例個數的連接、有顯示jvm中對象大小的連接等,點擊顯示jvm中對象大小的連接,獲得的結果如圖2所示。

 

 

圖2  jhat運行效果

 

  點擊圖2中的class [C,能夠看到有哪些對象實例引用了這個對象,或者建立了這個對象,jhat在分析大的堆dump文件時表現很差,速度很慢。

 

6. JStat

 

  JStat是Sun JDK自帶的一個統計分析JVM運行情況的工具,位於JDK的bin目錄下,除了可用於分析GC的情況外,還可用於分析編譯的情況、class加載的情況等。

 

  JStat用於GC分析的參數有:-gc、-gccapacity、-gccause、-gcnew、-gcnewcapacity、-gcold、-gcoldcapacity、-gcpermcapacity、-gcutil。經常使用的爲-gcutil。經過-gcutil可按必定頻率查看jvm中各代的空間的佔用狀況、minor GC的次數、消耗的時間、full GC的次數及消耗的時間的統計,執行jstat -gcutil [pid] [interval],可看到相似以下的輸出信息:

 

 

 

 S0     S1       E      O       P       YGC   
YGCT     FGC    FGCT     GCT   0.00   74.24  96.73  73.43  46.05  17808  
382.335   208  315.197  697.533  45.37   0.00   28.12  74.97  46.05  17809 
382.370   208  315.197  697.568

 

 

 

  其中S0、S1就是Survivor空間的使用率,E表示Eden空間的使用率,O表示舊生代空間的使用率,P表示持久代的使用率,YGC表示minor GC的執行次數,YGCT表示minor GC執行消耗的時間,FGC表示Full GC的執行次數,FGCT表示Full GC執行消耗的時間,GCT表示Minor GC+Full GC執行消耗的時間。

 

  7. Eclipse Memory Analyzer

 

  Eclipse Memory Analyzer是Eclipse提供的一個用於分析jvm堆dump文件的插件,藉助這個插件可查看對象的內存佔用情況、引用關係、分析內存泄露等。

 

  Eclipse Memory Analyzer(MAT)的網站爲:http://www.eclipse.org/mat/,在eclipse中能夠直接遠程安裝此插件。不過因爲此插件在分析堆dump文件時比較耗內存,所以在分析前最好先將eclipse的jvm的內存設置大一點,MAT分析dump文件後的對象佔用內存及引用關係如圖3所示。

 

  相對而言MAT功能比jhat強大不少,分析的速度也快一些,所以,若是要分析jvm堆dumap文件,首選推薦的是MAT。

 

  在進行JVM內存情況分析時,一般要關注的主要有GC的趨勢、內存的具體消耗情況。

 

  GC趨勢對於可圖形界面連到需查看GC情況的機器的狀況而言,VisualVM是經常使用的選擇;對於不能採用圖形界面方式的,輸出GC日誌 及採用jstat命令直接分析是經常使用的選擇。

 

  在查找內存是程序中的什麼對象佔用時,須要分析內存的具體消耗情況,對於有圖形界面可用的狀況,VisualVM是經常使用的選擇;對於不能採用圖形界面方式的,可經過jmap dump生成文件後,再經過MAT進行分析是經常使用的選擇。

相關文章
相關標籤/搜索