標籤:rri arch ips org 調優 準備 log4j 分享 sum
VisualVM 是一款免費的,整合了多個 JDK 命令列工具的視覺化檢視,它能為您提供強大的分析能力,對 Java 應用程式做效能分析和調優。這些功能包括產生和分析海量資料、跟蹤記憶體流失、監控記憶體回收行程、執行記憶體和 CPU 分析,同時它還支援在 MBeans 上進行瀏覽和操作。本文主要介紹如何使用 VisualVM 進行效能分析及調優。
目錄: 準備工作
記憶體分析篇 記憶體堆Heap 持續保留地區PermGen CPU分析篇 線程分析篇 參考文獻
準備工作
自從 JDK 6 Update 7 以後已經作為 Oracle JDK 的一部分,位於 JDK 根目錄的 bin 檔案夾下,無需安裝,直接運行即可。
記憶體分析篇
VisualVM 通過檢測 JVM 中載入的類和對象資訊等協助我們分析記憶體使用量情況,我們可以通過 VisualVM 的監視標籤對應用程式進行記憶體分析。
1)記憶體堆Heap
首先我們來看記憶體堆Heap使用方式,我本機eclipse的進程在visualVM顯示如下:
隨便寫個小程式佔用記憶體大的,運行一下
程式如下:
package jvisualVM;public class JavaHeapTest { public final static int OUTOFMEMORY = 200000000; private String oom; private int length; StringBuffer tempOOM = new StringBuffer(); public JavaHeapTest(int leng) { this.length = leng; int i = 0; while (i < leng) { i++; try { tempOOM.append("a"); } catch (OutOfMemoryError e) { e.printStackTrace(); break; } } this.oom = tempOOM.toString(); } public String getOom() { return oom; } public int getLength() { return length; } public static void main(String[] args) { JavaHeapTest javaHeapTest = new JavaHeapTest(OUTOFMEMORY); System.out.println(javaHeapTest.getOom().length()); }}
查看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)持續保留地區PermGen
其次來看下持續保留地區PermGen使用方式
運行一段類載入的程式,代碼如下:
package jvisualVM;import java.io.File;import java.lang.reflect.Method;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;import java.util.ArrayList;import java.util.List;public class TestPermGen { private static List<Object> insList = new ArrayList<Object>(); public static void main(String[] args) throws Exception { permLeak(); } private static void permLeak() throws Exception { for (int i = 0; i < 1000; i++) { URL[] urls = getURLS(); URLClassLoader urlClassloader = new URLClassLoader(urls, null); Class<?> logfClass = Class.forName("org.apache.commons.logging.LogFactory", true,urlClassloader); Method getLog = logfClass.getMethod("getLog", String.class); Object result = getLog.invoke(logfClass, "TestPermGen"); insList.add(result); System.out.println(i + ": " + result); } } private static URL[] getURLS() throws MalformedURLException { File libDir = new File("C:/Users/wadexu/.m2/repository/commons-logging/commons-logging/1.1.1"); File[] subFiles = libDir.listFiles(); int count = subFiles.length; URL[] urls = new URL[count]; for (int i = 0; i < count; i++) { urls[i] = subFiles[i].toURI().toURL(); } return urls; } }
一個類型裝載之後會建立一個對應的java.lang.Class執行個體,這個執行個體本身和普通對象執行個體一樣儲存於堆中,我覺得之所以說是這是一種特殊的執行個體,某種程度上是因為其充當了訪問PermGen地區中類型資訊的代理者。
運行一段時間後拋OutOfMemoryError了, VisualVM監控結果如下:
結論:PermGen地區分配的堆空間過小,我們可以通過設定-XX: PermSize參數和-XX:MaxPermSize參數來解決。
關於PermGen OOM深入分析請參考這篇文章
關於Perform GC, 請參考這篇文章
這部分知識還是比較深入的,有空還要繼續研究。
###轉載註明出處:http://www.cnblogs.com/wade-xu/p/4369094.html
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 能否分析出來
package jvisualVM;public class DeadLock { public static void main(String[] args) { Resource r1 = new Resource(); Resource r0 = new Resource(); Thread myTh1 = new LockThread1(r1, r0); Thread myTh0 = new LockThread0(r1, r0); myTh1.setName("DeadLock-1 "); myTh0.setName("DeadLock-0 "); myTh1.start(); myTh0.start(); }} class Resource { private int i; public int getI() { return i; } public void setI(int i) { this.i = i; } } class LockThread1 extends Thread { private Resource r1, r2; public LockThread1(Resource r1, Resource r2) { this.r1 = r1; this.r2 = r2; } @Override public void run() { int j = 0; while (true) { synchronized (r1) { System.out.println("The first thread got r1‘s lock " + j); synchronized (r2) { System.out.println("The first thread got r2‘s lock " + j); } } j++; } } } class LockThread0 extends Thread { private Resource r1, r2; public LockThread0(Resource r1, Resource r2) { this.r1 = r1; this.r2 = r2; } @Override public void run() { int j = 0; while (true) { synchronized (r2) { System.out.println("The second thread got r2‘s lock " + j); synchronized (r1) { System.out.println("The second thread got r1‘s lock" + j); } } j++; } } }
開啟VisualVM檢測到的JVM進程,我們可以看到這個tab在閃,VisualVM已經檢測到我這個package下面的DeadLock類出錯了
切換到Thread tab, 可以看到死結了, Deadlock detected!
另外可以點擊Thread Dump 線程轉儲,進一步分析,在這裡就不贅述了,有興趣的讀者可以自行實驗。
參考文獻:
http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/
轉自:http://www.cnblogs.com/wade-xu/p/4369094.html
深入理解java虛擬機器---虛擬機器工具VisualVM(十九)