[Java性能調(diào)優(yōu):利用VisualVM進行性能分析]
JVisualVM 簡介
VisualVM 是Netbeans的profile子項目瘪校,已在JDK6.0 update 7 中自帶,能夠監(jiān)控線程名段,內(nèi)存情況阱扬,查看方法的CPU時間和內(nèi)存中的對 象,已被GC的對象伸辟,反向查看分配的堆棧(如100個String對象分別由哪幾個對象分配出來的)麻惶。在JDK_HOME/bin(默認是C:\Program Files\Java\jdk1.6.0_13\bin)目錄下面,有一個jvisualvm.exe文件信夫,雙擊打開窃蹋,從UI上來看,這個軟件是基于NetBeans開發(fā)的了静稻。
VisualVM 提供了一個可視界面警没,用于查看 Java 虛擬機 (Java Virtual Machine, JVM) 上運行的基于 Java 技術(shù)的應用程序的詳細信息。VisualVM 對 Java Development Kit (JDK) 工具所檢索的 JVM 軟件相關(guān)數(shù)據(jù)進行組織振湾,并通過一種使您可以快速查看有關(guān)多個 Java 應用程序的數(shù)據(jù)的方式提供該信息杀迹。您可以查看本地應用程序或遠程主機上運行的應用程序的相關(guān)數(shù)據(jù)。此外押搪,還可以捕獲有關(guān) JVM 軟件實例的數(shù)據(jù)树酪,并將該數(shù)據(jù)保存到本地系統(tǒng)浅碾,以供后期查看或與其他用戶共享。
雙擊啟動 jvisualvm.exe续语,啟動起來后和jconsole 一樣同樣可以選擇本地和遠程垂谢,如果需要監(jiān)控遠程同樣需要配置相關(guān)參數(shù)。
主界面如下疮茄;
VisualVM可以根據(jù)需要安裝不同的插件滥朱,每個插件的關(guān)注點都不同,有的主要監(jiān)控GC娃豹,有的主要監(jiān)控內(nèi)存焚虱,有的監(jiān)控線程等。
如何安裝:
1懂版、從主菜單中選擇“工具”>“插件”鹃栽。
2、在“可用插件”標簽中躯畴,選中該插件的“安裝”復選框民鼓。單擊“安裝”。
3蓬抄、逐步完成插件安裝程序丰嘉。
我這里以 Eclipse(pid 22296)為例,雙擊后直接展開嚷缭,主界面展示了系統(tǒng)和jvm兩大塊內(nèi)容饮亏,點擊右下方j(luò)vm參數(shù)和系統(tǒng)屬性可以參考詳細的參數(shù)信息.
因為VisualVM的插件太多,我這里主要介紹三個我主要使用幾個:監(jiān)控阅爽、線程路幸、Visual GC
監(jiān)控的主頁其實也就是,cpu付翁、內(nèi)存简肴、類、線程的圖表
線程和jconsole功能沒有太大的區(qū)別
Visual GC 是常常使用的一個功能百侧,可以明顯的看到年輕代砰识、老年代的內(nèi)存變化,以及gc頻率佣渴、gc的時間等辫狼。
以上的功能其實jconsole幾乎也有,VisualVM更全面更直觀一些观话,另外VisualVM非常多的其它功能予借,可以分析dump的內(nèi)存快照,
dump出來的線程快照并且進行分析等,還有其它很多的插件大家可以去探索
案例分析
準備模擬內(nèi)存泄漏樣例
1灵迫、定義靜態(tài)變量HashMap
2秦叛、分段循環(huán)創(chuàng)建對象,并加入HashMap
代碼如下:
[](javascript:void(0); "復制代碼")
<pre style="margin-top: 0px; margin-bottom: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">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();
} //循環(huán)添加對象到緩存
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");
}
}</pre>
](javascript:void(0); "復制代碼")
3瀑粥、配置jvm參數(shù)如下:
-Xms512m
-Xmx512m
-XX:-UseGCOverheadLimit
-XX:MaxPermSize=50m
4挣跋、運行程序并打卡visualvm監(jiān)控
使用JVisualVM分析內(nèi)存泄漏
1、查看Visual GC標簽狞换,內(nèi)容如下避咆,這是輸出first的截圖

這是輸出forth的截圖:
通過2張圖對比發(fā)現(xiàn):
老生代一直在gc,當程序繼續(xù)運行可以發(fā)現(xiàn)老生代gc還在繼續(xù):
增加到了7次修噪,但是老生代的內(nèi)存并沒有減少查库。說明存在無法被回收的對象,可能是內(nèi)存泄漏了黄琼。
如何分析是那個對象泄漏了呢樊销?打開抽樣器標簽:點擊后如下圖:
按照程序輸出進行堆dump,當輸出second時脏款,dump一次围苫,當輸出forth時dump一次。
進入最后dump出來的堆標簽撤师,點擊類:
點擊右上角:“與另一個堆存儲對比”剂府。如圖選擇第一次導出的dump內(nèi)容比較:
比較結(jié)果如下:
可以看出在兩次間隔時間內(nèi)TestMemory對象實例一直在增加并且多了,說明該對象引用的方法可能存在內(nèi)存泄漏剃盾。
如何查看對象引用關(guān)系呢腺占?
右鍵選擇類TestMemory,選擇“在實例視圖中顯示”痒谴,如下所示:
左側(cè)是創(chuàng)建的實例總數(shù)湾笛,右側(cè)上部為該實例的結(jié)構(gòu),下面為引用說明闰歪,從圖中可以看出在類CyclicDependencies里面被引用了,并且被HashMap引用蓖墅。
如此可以確定泄漏的位置库倘,進而根據(jù)實際情況進行分析解決。
JVisualVM 遠程監(jiān)控 Tomcat
1论矾、修改遠程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"
這次配置先不走權(quán)限校驗。只是打開jmx端口贪壳。
2饱亿、打開jvisualvm,右鍵遠程,選擇添加遠程主機:

3彪笼、輸入主機的名稱钻注,直接寫ip,如下:
 右鍵新建的主機配猫,選擇添加JMX連接幅恋,輸入在tomcat中配置的端口即可。
4泵肄、雙擊打開捆交。完畢!
參考資料
https://blog.csdn.net/kl28978113/article/details/53817827
https://www.cnblogs.com/ityouknow/p/6437037.html