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


1.jvm監控工具介紹

1.1.jconsole

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

1.2.啟動jconsole

  通過JDK/bin目錄下的“jconsole.exe”啟動Jconsole后,將自動搜索出本機運行的所有虛擬機進程,雙擊其中一個進程即可開始監控。

  也可以“遠程連接服務器,進行遠程虛擬機的監控。

  

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

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

1.2.1.概覽頁面

  進入監控界面后如下圖

  

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

1.2.2.內存監控

  

1.2.3線程監控

  此處的線程監控,可以方便的進行死鎖檢測,非常重要

  

1.2.4.類加載監控

  

1.2.5.jvm報表

   

1.3.jvisualvm

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

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

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.死鎖的構成基本條件

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

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

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

4、循環等待條件:形成一種循環等待的場景

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.內存快照分析

    

    從內存快照中可以清楚的看到產生內存溢出的原因。

    

    內存占比列表。

    還有其他的功能,大家自己點擊查看。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM