java自帶的監控工具VisualVM

VisualVM 是一款免費的,集成了多個 JDK 命令行工具的可視化工具,它能爲您提供強大的分析能力,對 Java 應用程序做性能分析和調優。這些功能包括生成和分析海量數據、跟蹤內存泄漏、監控垃圾回收器、執行內存和 CPU 分析,同時它還支持在 MBeans 上進行瀏覽和操作。本文主要介紹如何使用 VisualVM 進行性能分析及調優。

http://visualvm.github.io/releases.html

到這個地址進行下載安裝   找到jdk對應VisualVM 的版本

 

 

 

準備工作

本文針對jdk1.8.0_131 進行驗證

 內存分析篇

VisualVM 通過檢測 JVM 中加載的類和對象信息等幫助我們分析內存使用情況,我們可以通過 VisualVM 的監視標籤對應用程序進行內存分析。

1)內存堆Heap

首先我們來看內存堆Heap使用情況,我本機eclipse的進程在visualVM顯示如下:

隨便寫個小程序佔用內存大的,運行一下

程序如下:

複製代碼

 1 package jvisualVM;
 2 
 3 public class JavaHeapTest {
 4     public final static int OUTOFMEMORY = 200000000;
 5     
 6     private String oom;
 7 
 8     private int length;
 9     
10     StringBuffer tempOOM = new StringBuffer();
11 
12     public JavaHeapTest(int leng) {
13         this.length = leng;
14        
15         int i = 0;
16         while (i < leng) {
17             i++;
18             try {
19                 tempOOM.append("a");
20             } catch (OutOfMemoryError e) {
21                e.printStackTrace();
22                break;
23             }
24         }
25         this.oom = tempOOM.toString();
26 
27     }
28 
29     public String getOom() {
30         return oom;
31     }
32 
33     public int getLength() {
34         return length;
35     }
36 
37     public static void main(String[] args) {
38         JavaHeapTest javaHeapTest = new JavaHeapTest(OUTOFMEMORY);
39         System.out.println(javaHeapTest.getOom().length());
40     }
41 
42 }

複製代碼

查看VisualVM Monitor tab, 堆內存變大了

在程序運行結束之前, 點擊Heap Dump 按鈕, 等待一會兒,得到dump結果,可以看到一些Summary信息

點擊Classes, 發現char[]所佔用的內存是最大的

雙擊它,得到如下Instances結果

Instances是按Size由大到小排列的

第一個就是最大的, 展開Field區域的 values

StringBuffer類型的 全局變量 tempOOM 佔用內存特別大, 注意局部變量是無法通過 堆dump來得到分析結果的。

另外,對於“堆 dump”來說,在遠程監控jvm的時候,VisualVM是沒有這個功能的,只有本地監控的時候纔有。

  ###轉載註明出處:http://www.cnblogs.com/wade-xu/p/4369094.html

 

2)·元空間metaspace

其次來看下元空間metaspace使用情況

運行一段類加載的程序,代碼如下:

複製代碼

 1 package jvisualVM;
 2 
 3 import java.io.File;
 4 import java.lang.reflect.Method;
 5 import java.net.MalformedURLException;
 6 import java.net.URL;
 7 import java.net.URLClassLoader;
 8 import java.util.ArrayList;
 9 import java.util.List;
10 
11 public class TestPermGen {
12     
13     private static List<Object> insList = new ArrayList<Object>();
14 
15     public static void main(String[] args) throws Exception {
16 
17         permLeak();
18     }
19 
20     private static void permLeak() throws Exception {
21         for (int i = 0; i < 1000; i++) {
22             URL[] urls = getURLS();
23             URLClassLoader urlClassloader = new URLClassLoader(urls, null);
24             Class<?> logfClass = Class.forName("org.apache.commons.logging.LogFactory", true,urlClassloader);
25             Method getLog = logfClass.getMethod("getLog", String.class);
26             Object result = getLog.invoke(logfClass, "TestPermGen");
27             insList.add(result);
28             System.out.println(i + ": " + result);
29         }
30     }
31 
32     private static URL[] getURLS() throws MalformedURLException {
33         File libDir = new File("C:/Users/wadexu/.m2/repository/commons-logging/commons-logging/1.1.1");
34         File[] subFiles = libDir.listFiles();
35         int count = subFiles.length;
36         URL[] urls = new URL[count];
37         for (int i = 0; i < count; i++) {
38             urls[i] = subFiles[i].toURI().toURL();
39         }
40         return urls;
41     }
42 
43     
44 }

複製代碼

 

 運行一段時間後拋OutOfMemoryError了, VisualVM監控結果如下:


 

 

 

CPU分析篇

CPU 性能分析的主要目的是統計函數的調用情況及執行時間,或者更簡單的情況就是統計應用程序的 CPU 使用情況。

沒有程序運行時的 CPU 使用情況如下圖:

 

運行一段 佔用CPU 的小程序,代碼如下

複製代碼

package jvisualVM;

public class MemoryCpuTest {

    public static void main(String[] args) throws InterruptedException {

        cpuFix();
    }


    /**
     * cpu 運行固定百分比
     * 
     * @throws InterruptedException
     */
    public static void cpuFix() throws InterruptedException {
        // 80%的佔有率
        int busyTime = 8;
        // 20%的佔有率
        int idelTime = 2;
        // 開始時間
        long startTime = 0;
        
        while (true) {
            // 開始時間
            startTime = System.currentTimeMillis();
            
            /*
             * 運行時間
             */
            while (System.currentTimeMillis() - startTime < busyTime) {
                ;
            }
            
            // 休息時間
            Thread.sleep(idelTime);
        }
    }
}

複製代碼

查看監視頁面 Monitor tab

 

過高的 CPU 使用率可能是由於我們的項目中存在低效的代碼;

在我們對程序施壓的時候,過低的 CPU 使用率也有可能是程序的問題。

 

點擊取樣器Sampler, 點擊“CPU”按鈕, 啓動CPU性能分析會話,VisualVM 會檢測應用程序所有的被調用的方法,

在CPU samples tab 下可以看到我們的方法cpufix() 的自用時間最長, 如下圖:

切換到Thread CPU Time 頁面下,我們的 main 函數這個進程 佔用CPU時間最長, 如下圖:

 ###轉載註明出處:http://www.cnblogs.com/wade-xu/p/4369094.html

線程分析篇

Java 語言能夠很好的實現多線程應用程序。當我們對一個多線程應用程序進行調試或者開發後期做性能調優的時候,往往需要了解當前程序中所有線程的運行狀態,是否有死鎖、熱鎖等情況的發生,從而分析系統可能存在的問題。

在 VisualVM 的監視標籤內,我們可以查看當前應用程序中所有活動線程(Live threads)和守護線程(Daemon threads)的數量等實時信息。

 

運行一段小程序,代碼如下:

複製代碼

package jvisualVM;

public class MyThread extends Thread{
    
    public static void main(String[] args) {
        
        MyThread mt1 = new MyThread("Thread a");
        MyThread mt2 = new MyThread("Thread b");
        
        mt1.setName("My-Thread-1 ");
        mt2.setName("My-Thread-2 ");
        
        mt1.start();
        mt2.start();
    }
    
    public MyThread(String name) {
    }

    public void run() {
        
        while (true) {
            
        }
    }
    

}

複製代碼

Live threads 從11增加兩個 變成13了

Daemon threads從8增加兩個 變成10了 

 

VisualVM 的線程標籤提供了三種視圖,默認會以時間線的方式展現, 如下圖:

可以看到兩個我們run的程序裏啓的線程:My-Thread-1 和 My-Thread-2

 

另外還有兩種視圖分別是表視圖和詳細信息視圖, 這裏看一下每個Thread的詳細視圖:

 ###轉載註明出處:http://www.cnblogs.com/wade-xu/p/4369094.html 

 再來一段死鎖的程序,看VisualVM 能否分析出來

按 Ctrl+C 複製代碼

 

按 Ctrl+C 複製代碼

打開VisualVM檢測到的JVM進程,我們可以看到這個tab在閃,VisualVM已經檢測到我這個package下面的DeadLock類出錯了

切換到Thread tab, 可以看到死鎖了, Deadlock detected!

另外可以點擊Thread Dump 線程轉儲,進一步分析,在這裏就不贅述了,有興趣的讀者可以自行實驗。

 

 

參考文獻:

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章