zoukankan      html  css  js  c++  java
  • 深入理解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.内存快照分析

        

        从内存快照中可以清楚的看到产生内存溢出的原因。

        

        内存占比列表。

        还有其他的功能,大家自己点击查看。

  • 相关阅读:
    Python的递归深度问题
    Python之多进程
    Python之多线程
    Git的基本操作
    ref与out区别
    Numpy基本操作
    面向对象中有哪些双下线方法及应用场景
    上下文管理
    Local与LocalStack
    基于列表实现栈
  • 原文地址:https://www.cnblogs.com/newAndHui/p/11105956.html
Copyright © 2011-2022 走看看