JVisualVM簡介與內存泄漏實戰分析

1、JVisualVM能作什麼html

      VisualVM 是Netbeans的profile子項目,已在JDK6.0 update 7 中自帶(java啓動時不須要特定參數,監控工具在bin/jvisualvm.exe),可以監控線程,內存狀況,查看方法的CPU時間和內存中的對 象,已被GC的對象,反向查看分配的堆棧(如100個String對象分別由哪幾個對象分配出來的)。java

     在JDK_HOME/bin(默認是C:\Program Files\Java\jdk1.6.0_13\bin)目錄下面,有一個jvisualvm.exe文件,雙擊打開,從UI上來看,這個軟件是基於NetBeans開發的了。linux

     能夠進行遠程和本地監控。遠程監控須要打開jmx,下面內容會提到。spring

     其默認頁面爲:緩存

左側分爲本地和遠程。雙擊本地中VisualVM線程,能夠看到以下監控內容:tomcat

具體的介紹參看:服務器

http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/併發

2、準備模擬內存泄漏demojvm

      一、定義靜態變量HashMapide

      二、分段循環建立對象,並加入HashMap

      代碼以下:

import java.util.HashMap;

import java.util.Map;

public class CyclicDependencies {

    //聲明緩存對象

    private static final Map map = new HashMap();

    public static void main(String args[]){

        try {

            Thread.sleep(10000);//給打開visualvm時間

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        //循環添加對象到緩存

        for(int i=0; i<1000000;i++){

            TestMemory t = new TestMemory();

            map.put("key"+i,t);

        }

        System.out.println("first");

        //爲dump出堆提供時間

        try {

            Thread.sleep(10000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        for(int i=0; i<1000000;i++){

            TestMemory t = new TestMemory();

            map.put("key"+i,t);

        }

        System.out.println("second");

        try {

            Thread.sleep(10000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        for(int i=0; i<3000000;i++){

            TestMemory t = new TestMemory();

            map.put("key"+i,t);

        }

        System.out.println("third");

        try {

            Thread.sleep(10000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        for(int i=0; i<4000000;i++){

            TestMemory t = new TestMemory();

            map.put("key"+i,t);

        }

        System.out.println("forth");

        try {

            Thread.sleep(Integer.MAX_VALUE);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        System.out.println("qqqq");

    }

}

     三、配置jvm參數以下:

          -Xms512m

-Xmx512m

          -XX:-UseGCOverheadLimit

          -XX:MaxPermSize=50m

     四、運行程序並打卡visualvm監控

3、使用jVisualvm分析內存泄漏

      一、查看Visual GC標籤,內容以下,這是輸出first的截圖

            

這是輸出forth的截圖:

經過2張圖對比發現:

老生代一直在gc,當程序繼續運行能夠發現老生代gc還在繼續:

增長到了7次,可是老生代的內存並無減小。說明存在沒法被回收的對象,多是內存泄漏了。

如何分析是那個對象泄漏了呢?打開抽樣器標籤:點擊後以下圖:

按照程序輸出進行堆dump,當輸出second時,dump一次,當輸出forth時dump一次。

進入最後dump出來的堆標籤,點擊類:

點擊右上角:「與另外一個堆存儲對比」。如圖選擇第一次導出的dump內容比較:

比較結果以下:

能夠看出在兩次間隔時間內TestMemory對象實例一直在增長而且多了,說明該對象引用的方法可能存在內存泄漏。

如何查看對象引用關係呢?

右鍵選擇類TestMemory,選擇「在實例視圖中顯示」,以下所示:

左側是建立的實例總數,右側上部爲該實例的結構,下面爲引用說明,從圖中能夠看出在類CyclicDependencies裏面被引用了,而且被HashMap引用。

如此能夠肯定泄漏的位置,進而根據實際狀況進行分析解決。

4、jVisualvm遠程監控tomcat

     一、修改遠程tomcat的catalina.sh配置文件,在其中增長:

          JAVA_OPTS="$JAVA_OPTS

          -Djava.rmi.server.hostname=192.168.122.128

          -Dcom.sun.management.jmxremote.port=18999

-Dcom.sun.management.jmxremote.ssl=false

-Dcom.sun.management.jmxremote.authenticate=false"

此次配置先不走權限校驗。只是打開jmx端口。

    二、打開jvisualvm,右鍵遠程,選擇添加遠程主機:

          

   三、輸入主機的名稱,直接寫ip,以下:

          

        右鍵新建的主機,選擇添加JMX鏈接,輸入在tomcat中配置的端口便可。

   四、雙擊打開。完畢!

5、擴展知識

線程死鎖偵測

jvm優化建議

     本質上是減小GC的次數。

若是是頻繁建立對象的應用,能夠適當增長新生代大小。常量較多能夠增長持久代大小。對於單例較多的對象能夠增長老生代大小。好比spring應用中。

GC選擇,在JDK5.0之後,JVM會根據當前系統配置進行判斷。通常執行-Server命令即可以。gc包括三種策略:串行,並行,併發。

吞吐量大大應用,通常採用並行收集,開啓多個線程,加快gc的是否。

響應速度高的應用,通常採用併發收集,好比應用服務器。

     年老代建議配置爲併發收集器,因爲併發收集器不會壓縮和整理磁盤碎片,所以建議配置:

     -XX:+UseConcMarkSweepGC  #併發收集年老代

     -XX:CMSInitiatingOccupancyFraction=80 # 表示年老代空間到80%時就開始執行CMS

     -XX:+UseCMSCompactAtFullCollection # 打開對年老代的壓縮。可能會影響性能,可是能夠消除內存碎片。 

     -XX:CMSFullGCsBeforeCompaction=10 # 因爲併發收集器不對內存空間進行壓縮、整理,因此運行一段時間之後會產生「碎片」,使得運行效率下降。此參數設置運行次FullGC之後對內存空間進行壓縮、整理。 

直接運行linux上的jvisualvm

     下載X-Manager,能夠將試圖展示在本地機器上。

不受此jvm支持

保證jvisualvm所屬jdk版本和linux上一致。

相關文章
相關標籤/搜索