深刻理解jvm--性能監控工具

1.jvm監控工具介紹

1.1.jconsole

  JConsole是一個基於JMX的GUI工具,用於鏈接正在運行的JVM,不過此JVM須要使用可管理的模式啓動。html

1.2.啓動jconsole

  經過JDK/bin目錄下的「jconsole.exe」啓動Jconsole後,將自動搜索出本機運行的全部虛擬機進程,雙擊其中一個進程便可開始監控。java

  也能夠「遠程鏈接服務器,進行遠程虛擬機的監控。服務器

  

  補充:根據端口號查看進程jvm

  netstat -ano |findstr 8080
  解釋:|findstr 8080 表示過濾出包括8080的數據,至關於關鍵字查找ide

1.2.1.概覽頁面

  進入監控界面後以下圖工具

  

  概述頁面顯示的是整個虛擬機主要運行數據的概覽。測試

1.2.2.內存監控

  

1.2.3線程監控

  此處的線程監控,能夠方便的進行死鎖檢測,很是重要ui

  

1.2.4.類加載監控

  

1.2.5.jvm報表

   

1.3.jvisualvm

  提供了和jconsole的功能相似,提供了一大堆的插件。
  插件中,Visual GC(可視化GC)仍是比較好用的,可視化GC能夠看到內存的具體使用狀況。this

  啓動方式,打開java安裝目錄,啓動 bin/jvisualvm.exe 應用。url

2.內存溢出實戰模擬

  本節將以實際案例結合上面的jvm監控工具,深刻的理解jvm!

2.1.案例一:內存溢出實戰模擬

  測試代碼:

 1 package com.wfd360.outofmemory;  2 
 3 import java.util.ArrayList;  4 
 5 /**
 6  * VM Args:  7  * -Xms20m -Xmx20m  8  */
 9 public class TestMemory { 10     static class OOMObject { 11         public byte[] byt = new byte[1 * 1024 * 1024]; 12  } 13 
14     public static void main(String[] args) throws Exception { 15         Thread.sleep(10000); 16         fillHeap(100); 17         Thread.sleep(10000); 18  } 19 
20     public static void fillHeap(int num) throws Exception { 21         ArrayList<OOMObject> list = new ArrayList<OOMObject>(); 22         for (int i = 0; i < num; i++) { 23             Thread.sleep(500); 24             list.add(new OOMObject()); 25             System.out.println("num=" + i); 26  } 27  System.gc(); 28  } 29 
30 
31 }
View Code

  測試jvm參數設置:

  

  測試結果:

  當建立第16個對象時,內存溢出

  

  可視化內存信息觀察:

  

  分代回收機制理解:

  https://www.cnblogs.com/newAndHui/p/11106232.html

2.2.案例二:線程的異常等待與異常運行

  測試代碼以下:

 1 package com.wfd360.outofmemory;  2 
 3 import java.io.BufferedReader;  4 import java.io.InputStreamReader;  5 
 6 public class TestThread {  7     /**
 8  * 死循環演示  9  * 10      */
11     public static void createBusyThread() { 12         Thread thread = new Thread(new Runnable() { 13  @Override 14             public void run() { 15                 System.out.println("createBusyThread"); 16                 while (true) 17  ; 18  } 19         }, "testBusyThread"); 20  thread.start(); 21  } 22 
23     /**
24  * 線程鎖等待 25  * 26      */
27     public static void createLockThread(final Object lock) { 28         Thread thread = new Thread(new Runnable() { 29  @Override 30             public void run() { 31                 System.out.println("createLockThread"); 32                 synchronized (lock) { 33                     try { 34  lock.wait(); 35                     } catch (InterruptedException e) { 36  e.printStackTrace(); 37  } 38  } 39 
40  } 41         }, "testLockThread"); 42  thread.start(); 43  } 44     public static void main(String[] args) throws Exception { 45         BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 46  br.readLine(); 47  createBusyThread(); 48  br.readLine(); 49         Object object = new Object(); 50  createLockThread(object); 51  } 52 }
View Code

 

   線程監視圖:

  

  線程dump:

   

  總結:經過線程可視化觀察,「testLockThread」線程一直處於等待狀態,那麼咱們就可使用dump,導出堆棧信息,查看具體緣由。

2.3.案例三:線程死鎖實戰演示

   測試代碼:

 1 package com.wfd360.thread;  2 
 3 public class DeadThread implements Runnable {  4     //控制鎖順序
 5     private boolean lockFormer;  6     //對象1
 7     private static Object o1 = new Object();  8     //對象2
 9     private static Object o2 = new Object(); 10 
11     DeadThread(boolean lockFormer) { 12         this.lockFormer = lockFormer; 13  } 14 
15  @Override 16     public void run() { 17         if (this.lockFormer) { 18             synchronized (o1) { 19                 try { 20                     Thread.sleep(500); 21                 } catch (InterruptedException e) { 22  e.printStackTrace(); 23  } 24                 synchronized (o2) { 25                     System.out.println("1ok"); 26  } 27  } 28         } else { 29             synchronized (o2) { 30                 try { 31                     Thread.sleep(500); 32                 } catch (InterruptedException e) { 33  e.printStackTrace(); 34  } 35                 synchronized (o1) { 36                     System.out.println("2ok"); 37  } 38  } 39  } 40  } 41 
42     public static void main(String[] args) { 43         for (int i = 0; i < 200; i++) { 44             new Thread(new DeadThread(true)).start(); 45             new Thread(new DeadThread(false)).start(); 46  } 47  } 48 }
View Code

 

   jvm內存監控觀察:

  

  死鎖檢測:

  

2.3.1.死鎖的構成基本條件

一、互斥條件:一份資源每次只能被一個進程或線程使用(在Java中通常體現爲,一個對象鎖只能被一個線程持有)

二、請求與保持條件:一個進程或線程在等待請求資源被釋放時,不釋放已佔有資源

三、不可剝奪條件:一個進程或線程已經得到的資源不能被其餘進程或線程強行剝奪

四、循環等待條件:造成一種循環等待的場景

2.4.案例四:內存快照分析

  測試代碼:

 1 package com.wfd360.outofmemory;  2 
 3 import java.util.ArrayList;  4 import java.util.List;  5 
 6 /**
 7  * 演示堆內存溢出  8  * 配置jvm參數  9  * VM Args: 10  * -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=f:/test/dump 11  * 參數-XX:+HeapDumpOnOutOfMemoryError可讓虛擬機在出現內存溢出異常時Dump出當前的內存堆轉儲快照以便過後進行分析,文件在項目中 12  */
13 public class HeapOOM { 14     static class OOMObject { 15         public byte[] byt = new byte[1 * 1024*1024]; 16  } 17 
18     public static void main(String[] args) { 19         List<OOMObject> list = new ArrayList<OOMObject>(); 20         while (true) { 21             list.add(new OOMObject()); 22  } 23  } 24 }
View Code

   jvm參數配置:

  

  測試結果:

  

   這時生產的內存快照在 f:/test/dump 中

  接下來,使用工具分析內存快照:

  1.解壓 MemoryAnalyzer-1.5.0.20150527-win32.win32.x86_64.zip

    百度網盤下載連接:https://pan.baidu.com/s/1NYzO2ykruGAURg2SrPJqCQ
    提取碼:mtqc
  2.啓動 MemoryAnalyzer.exe

    

  3.打開剛纔生成的內存快照  f:/test/dump 

    

  4.內存快照分析

    

    從內存快照中能夠清楚的看到產生內存溢出的緣由。

    

    內存佔比列表。

    還有其餘的功能,你們本身點擊查看。

相關文章
相關標籤/搜索