使用 VisualVM 進行性能分析及調(diào)優(yōu)

轉(zhuǎn)自:http://www.cnblogs.com/wade-xu/p/4369094.html

這篇總結(jié)的很不錯(本人親自操手學(xué)習(xí))鲫懒,留著以后復(fù)習(xí)備用诡壁,很適合入門級的學(xué)習(xí)者:

VisualVM 是一款免費的逃沿,集成了多個 JDK 命令行工具的可視化工具,它能為您提供強大的分析能力唉韭,對 Java 應(yīng)用程序做性能分析和調(diào)優(yōu)柔逼。這些功能包括生成和分析海量數(shù)據(jù)、跟蹤內(nèi)存泄漏享钞、監(jiān)控垃圾回收器揍诽、執(zhí)行內(nèi)存和 CPU 分析,同時它還支持在 MBeans 上進行瀏覽和操作栗竖。本文主要介紹如何使用 VisualVM 進行性能分析及調(diào)優(yōu)暑脆。

準(zhǔn)備工作

自從 JDK 6 Update 7 以后已經(jīng)作為 Oracle JDK 的一部分,位于 JDK 根目錄的 bin 文件夾下狐肢,無需安裝添吗,直接運行即可。

?內(nèi)存分析篇

VisualVM 通過檢測 JVM 中加載的類和對象信息等幫助我們分析內(nèi)存使用情況份名,我們可以通過 VisualVM 的監(jiān)視標(biāo)簽對應(yīng)用程序進行內(nèi)存分析碟联。

1)內(nèi)存堆Heap

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

隨便寫個小程序占用內(nèi)存大的僵腺,運行一下

程序如下:

1package jvisualVM; 2 3publicclass JavaHeapTest { 4publicfinalstaticintOUTOFMEMORY = 200000000; 5 6private String oom; 7 8privateint length; 910StringBuffer tempOOM =new StringBuffer();1112publicJavaHeapTest(int leng) {13this.length = leng;1415inti = 0;16while(i < leng) {17i++;18try {19tempOOM.append("a");20}catch (OutOfMemoryError e) {21? ? ? ? ? ? ? e.printStackTrace();22break;23? ? ? ? ? ? }24? ? ? ? }25this.oom = tempOOM.toString();2627? ? }2829public String getOom() {30return oom;31? ? }3233publicint getLength() {34return length;35? ? }3637publicstaticvoid main(String[] args) {38JavaHeapTest javaHeapTest =new JavaHeapTest(OUTOFMEMORY);39? ? ? ? System.out.println(javaHeapTest.getOom().length());40? ? }4142}

查看VisualVM Monitor tab, 堆內(nèi)存變大了

在程序運行結(jié)束之前鲤孵, 點擊Heap Dump 按鈕, 等待一會兒辰如,得到dump結(jié)果普监,可以看到一些Summary信息

點擊Classes,?發(fā)現(xiàn)char[]所占用的內(nèi)存是最大的

雙擊它琉兜,得到如下Instances結(jié)果

Instances是按Size由大到小排列的

第一個就是最大的凯正, 展開Field區(qū)域的 values

StringBuffer類型的 全局變量 tempOOM 占用內(nèi)存特別大, 注意局部變量是無法通過 堆dump來得到分析結(jié)果的呕童。

另外漆际,對于“堆 dump”來說淆珊,在遠程監(jiān)控jvm的時候夺饲,VisualVM是沒有這個功能的,只有本地監(jiān)控的時候才有。

###轉(zhuǎn)載注明出處:http://www.cnblogs.com/wade-xu/p/4369094.html


2)永久保留區(qū)域PermGen

其次來看下永久保留區(qū)域PermGen使用情況

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

1package jvisualVM; 2 3import java.io.File; 4import java.lang.reflect.Method; 5import java.net.MalformedURLException; 6import java.net.URL; 7import java.net.URLClassLoader; 8import java.util.ArrayList; 9import java.util.List;1011publicclass TestPermGen {1213privatestaticList insList =newArrayList();1415publicstaticvoidmain(String[] args)throws Exception {1617? ? ? ? permLeak();18? ? }1920privatestaticvoidpermLeak()throws Exception {21for(inti = 0; i < 1000; i++) {22URL[] urls = getURLS();23URLClassLoader urlClassloader =newURLClassLoader(urls,null);24Class logfClass = Class.forName("org.apache.commons.logging.LogFactory",true,urlClassloader);25Method getLog = logfClass.getMethod("getLog", String.class);26Object result = getLog.invoke(logfClass, "TestPermGen");27? ? ? ? ? ? insList.add(result);28System.out.println(i + ": " + result);29? ? ? ? }30? ? }3132privatestaticURL[] getURLS()throws MalformedURLException {33File libDir =newFile("C:/Users/wadexu/.m2/repository/commons-logging/commons-logging/1.1.1");34File[] subFiles = libDir.listFiles();35intcount = subFiles.length;36URL[] urls =new URL[count];37for(inti = 0; i < count; i++) {38urls[i] = subFiles[i].toURI().toURL();39? ? ? ? }40return urls;41? ? }424344}

一個類型裝載之后會創(chuàng)建一個對應(yīng)的java.lang.Class實例擂找,這個實例本身和普通對象實例一樣存儲于堆中,我覺得之所以說是這是一種特殊的實例浩销,某種程度上是因為其充當(dāng)了訪問PermGen區(qū)域中類型信息的代理者贯涎。

?運行一段時間后拋OutOfMemoryError了, VisualVM監(jiān)控結(jié)果如下:

結(jié)論:PermGen區(qū)域分配的堆空間過小慢洋,我們可以通過設(shè)置-XX: PermSize參數(shù)和-XX:MaxPermSize參數(shù)來解決塘雳。

關(guān)于PermGen OOM深入分析請參考這篇文章

關(guān)于Perform GC, 請參考這篇文章

###轉(zhuǎn)載注明出處:http://www.cnblogs.com/wade-xu/p/4369094.html


CPU分析篇

CPU 性能分析的主要目的是統(tǒng)計函數(shù)的調(diào)用情況及執(zhí)行時間,或者更簡單的情況就是統(tǒng)計應(yīng)用程序的 CPU 使用情況普筹。

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


運行一段 占用CPU 的小程序败明,代碼如下

package jvisualVM;publicclass MemoryCpuTest {

? ? publicstaticvoidmain(String[] args)throws InterruptedException {

? ? ? ? cpuFix();

? ? }

? ? /**? ? * cpu 運行固定百分比

? ? *

? ? * @throws InterruptedException

? ? */publicstaticvoidcpuFix()throws InterruptedException {

? ? ? ? // 80%的占有率intbusyTime = 8;

? ? ? ? // 20%的占有率intidelTime = 2;

? ? ? ? // 開始時間longstartTime = 0;


? ? ? ? while(true) {

? ? ? ? ? ? // 開始時間startTime = System.currentTimeMillis();


? ? ? ? ? ? /*? ? ? ? ? ? * 運行時間

? ? ? ? ? ? */while(System.currentTimeMillis() - startTime < busyTime) {

? ? ? ? ? ? ? ? ;

? ? ? ? ? ? }


? ? ? ? ? ? // 休息時間? ? ? ? ? ? Thread.sleep(idelTime);

? ? ? ? }

? ? }

}

查看監(jiān)視頁面 Monitor tab


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

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


點擊取樣器Sampler, 點擊“CPU”按鈕蜒车, 啟動CPU性能分析會話讳嘱,VisualVM 會檢測應(yīng)用程序所有的被調(diào)用的方法,

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

切換到Thread CPU Time 頁面下沥潭,我們的 main 函數(shù)這個進程 占用CPU時間最長, 如下圖:

###轉(zhuǎn)載注明出處:http://www.cnblogs.com/wade-xu/p/4369094.html

線程分析篇

Java 語言能夠很好的實現(xiàn)多線程應(yīng)用程序嬉挡。當(dāng)我們對一個多線程應(yīng)用程序進行調(diào)試或者開發(fā)后期做性能調(diào)優(yōu)的時候叛氨,往往需要了解當(dāng)前程序中所有線程的運行狀態(tài),是否有死鎖棘伴、熱鎖等情況的發(fā)生寞埠,從而分析系統(tǒng)可能存在的問題。

在 VisualVM 的監(jiān)視標(biāo)簽內(nèi)焊夸,我們可以查看當(dāng)前應(yīng)用程序中所有活動線程(Live threads)和守護線程(Daemon threads)的數(shù)量等實時信息仁连。


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

package jvisualVM;publicclassMyThreadextends Thread{


? ? publicstaticvoid main(String[] args) {


? ? ? ? MyThread mt1 =newMyThread("Thread a");

? ? ? ? MyThread mt2 =newMyThread("Thread b");


? ? ? ? mt1.setName("My-Thread-1 ");

? ? ? ? mt2.setName("My-Thread-2 ");


? ? ? ? mt1.start();

? ? ? ? mt2.start();

? ? }


? ? public MyThread(String name) {

? ? }

? ? publicvoid run() {


? ? ? ? while(true) {


? ? ? ? }

? ? }


}

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

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


VisualVM 的線程標(biāo)簽提供了三種視圖阱穗,默認會以時間線的方式展現(xiàn)饭冬, 如下圖:

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


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

###轉(zhuǎn)載注明出處:http://www.cnblogs.com/wade-xu/p/4369094.html

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

package jvisualVM;publicclass DeadLock {

? ? publicstaticvoid 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 {

? ? ? ? privateint i;


? ? ? ? publicint getI() {

? ? ? ? ? ? return i;

? ? ? ? }


? ? ? ? publicvoidsetI(int i) {

? ? ? ? ? ? this.i = i;

? ? ? ? }


? ? }

? ? classLockThread1extends Thread {

? ? ? ? private Resource r1, r2;


? ? ? ? public LockThread1(Resource r1, Resource r2) {

? ? ? ? ? ? this.r1 = r1;

? ? ? ? ? ? this.r2 = r2;

? ? ? ? }


? ? ? ? @Override

? ? ? ? publicvoid run() {

? ? ? ? ? ? intj = 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++;

? ? ? ? ? ? }

? ? ? ? }


? ? }

? ? classLockThread0extends Thread {

? ? ? ? private Resource r1, r2;


? ? ? ? public LockThread0(Resource r1, Resource r2) {

? ? ? ? ? ? this.r1 = r1;

? ? ? ? ? ? this.r2 = r2;

? ? ? ? }


? ? ? ? @Override

? ? ? ? publicvoid run() {

? ? ? ? ? ? intj = 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已經(jīng)檢測到我這個package下面的DeadLock類出錯了

切換到Thread tab鲁僚, 可以看到死鎖了炊苫,?Deadlock detected!

另外可以點擊Thread Dump 線程轉(zhuǎn)儲裁厅,進一步分析,在這里就不贅述了侨艾,有興趣的讀者可以自行實驗执虹。


參考文獻:

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市唠梨,隨后出現(xiàn)的幾起案子袋励,更是在濱河造成了極大的恐慌,老刑警劉巖当叭,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茬故,死亡現(xiàn)場離奇詭異,居然都是意外死亡蚁鳖,警方通過查閱死者的電腦和手機均牢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來才睹,“玉大人徘跪,你說我怎么就攤上這事±湃粒” “怎么了垮庐?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長坞琴。 經(jīng)常有香客問我哨查,道長,這世上最難降的妖魔是什么剧辐? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任寒亥,我火速辦了婚禮,結(jié)果婚禮上荧关,老公的妹妹穿的比我還像新娘溉奕。我一直安慰自己,他們只是感情好忍啤,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布加勤。 她就那樣靜靜地躺著,像睡著了一般同波。 火紅的嫁衣襯著肌膚如雪鳄梅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天未檩,我揣著相機與錄音戴尸,去河邊找鬼。 笑死冤狡,一個胖子當(dāng)著我的面吹牛孙蒙,可吹牛的內(nèi)容都是我干的项棠。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼马篮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怜奖?” 一聲冷哼從身側(cè)響起浑测,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎歪玲,沒想到半個月后迁央,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡滥崩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年岖圈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钙皮。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜂科,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出短条,到底是詐尸還是另有隱情导匣,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布茸时,位于F島的核電站贡定,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏可都。R本人自食惡果不足惜缓待,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渠牲。 院中可真熱鬧旋炒,春花似錦、人聲如沸签杈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芹壕。三九已至汇四,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間踢涌,已是汗流浹背通孽。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留睁壁,地道東北人背苦。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓互捌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親行剂。 傳聞我的和親對象是個殘疾皇子秕噪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • VisualVM 是一款免費的,集成了多個 JDK 命令行工具的可視化工具厚宰,它能為您提供強大的分析能力腌巾,對 Jav...
    Ag劉曉婷閱讀 819評論 0 1
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法铲觉,內(nèi)部類的語法澈蝙,繼承相關(guān)的語法,異常的語法撵幽,線程的語...
    子非魚_t_閱讀 31,599評論 18 399
  • Xmas * 特別限量版 這一抹紅灯荧,驚艷了時光
    URoom一室一品閱讀 133評論 0 0
  • 未裝修完的運動場逗载,跑道一層一層地被剝開,瀝青的填充裸露在外——“一個現(xiàn)代病的代言人链烈,只有剛鋪上才會有被燒焦的味道撕贞。...
    十七秒閱讀 256評論 1 2