1. 程式人生 > >JVisualVM簡介與內存泄漏實戰分析

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

action jvm優化 string tools html 時間 data 應用服務器 tom

一、JVisualVM能做什麽 VisualVM 是Netbeans的profile子項目,已在JDK6.0 update 7 中自帶(java啟動時不需要特定參數,監控工具在bin/jvisualvm.exe),能夠監控線程,內存情況,查看方法的CPU時間和內存中的對 象,已被GC的對象,反向查看分配的堆棧(如100個String對象分別由哪幾個對象分配出來的)。 在JDK_HOME/bin(默認是C:\Program Files\Java\jdk1.6.0_13\bin)目錄下面,有一個jvisualvm.exe文件,雙擊打開,從UI上來看,這個軟件是基於NetBeans開發的了。 可以進行遠程和本地監控。遠程監控需要打開jmx,下面內容會提到。 其默認頁面為: 技術分享
左側分為本地和遠程。雙擊本地中VisualVM線程,可以看到如下監控內容: 技術分享 具體的介紹參看: http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/ 二、準備模擬內存泄漏demo 1、定義靜態變量HashMap 2、分段循環創建對象,並加入HashMap 代碼如下: [java] view plain copy print?
  1. import java.util.HashMap;
  2. import java.util.Map;
  3. public class CyclicDependencies {
  4. //聲明緩存對象
  5. private static final Map map = new HashMap();
  6. public static void main(String args[]){
  7. try {
  8. Thread.sleep(10000);//給打開visualvm時間
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. //循環添加對象到緩存
  13. for(int i=0; i<1000000;i++){
  14. TestMemory t = new TestMemory();
  15. map.put("key"+i,t);
  16. }
  17. System.out.println("first");
  18. //為dump出堆提供時間
  19. try {
  20. Thread.sleep(10000);
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. for(int i=0; i<1000000;i++){
  25. TestMemory t = new TestMemory();
  26. map.put("key"+i,t);
  27. }
  28. System.out.println("second");
  29. try {
  30. Thread.sleep(10000);
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }
  34. for(int i=0; i<3000000;i++){
  35. TestMemory t = new TestMemory();
  36. map.put("key"+i,t);
  37. }
  38. System.out.println("third");
  39. try {
  40. Thread.sleep(10000);
  41. } catch (InterruptedException e) {
  42. e.printStackTrace();
  43. }
  44. for(int i=0; i<4000000;i++){
  45. TestMemory t = new TestMemory();
  46. map.put("key"+i,t);
  47. }
  48. System.out.println("forth");
  49. try {
  50. Thread.sleep(Integer.MAX_VALUE);
  51. } catch (InterruptedException e) {
  52. e.printStackTrace();
  53. }
  54. System.out.println("qqqq");
  55. }
  56. }
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");
    }
}
3、配置jvm參數如下: [plain] view plain copy print?
  1. -Xms512m
  2. -Xmx512m
  3. -XX:-UseGCOverheadLimit
  4. -XX:MaxPermSize=50m
         -Xms512m
         -Xmx512m
          -XX:-UseGCOverheadLimit
          -XX:MaxPermSize=50m
4、運行程序並打卡visualvm監控 三、使用jVisualvm分析內存泄漏 1、查看Visual GC標簽,內容如下,這是輸出first的截圖 技術分享 這是輸出forth的截圖: 技術分享 通過2張圖對比發現: 技術分享 技術分享 老生代一直在gc,當程序繼續運行可以發現老生代gc還在繼續: 技術分享 增加到了7次,但是老生代的內存並沒有減少。說明存在無法被回收的對象,可能是內存泄漏了。 如何分析是那個對象泄漏了呢?打開抽樣器標簽:點擊後如下圖: 技術分享 按照程序輸出進行堆dump,當輸出second時,dump一次,當輸出forth時dump一次。 進入最後dump出來的堆標簽,點擊類: 技術分享 點擊右上角:“與另一個堆存儲對比”。如圖選擇第一次導出的dump內容比較: 技術分享 比較結果如下: 技術分享 可以看出在兩次間隔時間內TestMemory對象實例一直在增加並且多了,說明該對象引用的方法可能存在內存泄漏。 如何查看對象引用關系呢? 右鍵選擇類TestMemory,選擇“在實例視圖中顯示”,如下所示: 技術分享 左側是創建的實例總數,右側上部為該實例的結構,下面為引用說明,從圖中可以看出在類CyclicDependencies裏面被引用了,並且被HashMap引用。 如此可以確定泄漏的位置,進而根據實際情況進行分析解決。 四、jVisualvm遠程監控tomcat 1、修改遠程tomcat的catalina.sh配置文件,在其中增加: [plain] view plain copy print?
  1. JAVA_OPTS="$JAVA_OPTS
  2. -Djava.rmi.server.hostname=192.168.122.128
  3. -Dcom.sun.management.jmxremote.port=18999
  4. -Dcom.sun.management.jmxremote.ssl=false
  5. -Dcom.sun.management.jmxremote.authenticate=false"
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端口。 2、打開jvisualvm,右鍵遠程,選擇添加遠程主機: 技術分享 3、輸入主機的名稱,直接寫ip,如下: 技術分享 右鍵新建的主機,選擇添加JMX連接,輸入在tomcat中配置的端口即可。 4、雙擊打開。完畢! 五、擴展知識 線程死鎖偵測 jvm優化建議 本質上是減少GC的次數。 如果是頻繁創建對象的應用,可以適當增加新生代大小。常量較多可以增加持久代大小。對於單例較多的對象可以增加老生代大小。比如spring應用中。 GC選擇,在JDK5.0以後,JVM會根據當前系統配置進行判斷。一般執行-Server命令便可以。gc包括三種策略:串行,並行,並發。 吞吐量大大應用,一般采用並行收集,開啟多個線程,加快gc的是否。 響應速度高的應用,一般采用並發收集,比如應用服務器。 年老代建議配置為並發收集器,由於並發收集器不會壓縮和整理磁盤碎片,因此建議配置: [plain] view plain copy print?
  1. -XX:+UseConcMarkSweepGC #並發收集年老代
  2. -XX:CMSInitiatingOccupancyFraction=80 # 表示年老代空間到80%時就開始執行CMS
  3. -XX:+UseCMSCompactAtFullCollection # 打開對年老代的壓縮。可能會影響性能,但是可以消除內存碎片。
  4. -XX:CMSFullGCsBeforeCompaction=10 # 由於並發收集器不對內存空間進行壓縮、整理,所以運行一段時間以後會產生“碎片”,使得運行效率降低。此參數設置運行次
    -XX:+UseConcMarkSweepGC  #並發收集年老代
     -XX:CMSInitiatingOccupancyFraction=80 # 表示年老代空間到80%時就開始執行CMS
     -XX:+UseCMSCompactAtFullCollection # 打開對年老代的壓縮。可能會影響性能,但是可以消除內存碎片。 
     -XX:CMSFullGCsBeforeCompaction=10 # 由於並發收集器不對內存空間進行壓縮、整理,所以運行一段時間以後會產生“碎片”,使得運行效率降低。此參數設置運行次
FullGC以後對內存空間進行壓縮、整理。 直接運行linux上的jvisualvm 下載X-Manager,可以將試圖展現在本地機器上。 不受此jvm支持 保證jvisualvm所屬jdk版本和linux上一致。

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