深入理解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.案例一:内存溢出实战模拟

  测试代码:

package com.wfd360.outofmemory;

import java.util.ArrayList;

/**
 * VM Args:
 * -Xms20m -Xmx20m
 */
public class TestMemory {
    static class OOMObject {
        public byte[] byt = new byte[1 * 1024 * 1024];
    }

    public static void main(String[] args) throws Exception {
        Thread.sleep(10000);
        fillHeap(100);
        Thread.sleep(10000);
    }

    public static void fillHeap(int num) throws Exception {
        ArrayList<OOMObject> list = new ArrayList<OOMObject>();
        for (int i = 0; i < num; i++) {
            Thread.sleep(500);
            list.add(new OOMObject());
            System.out.println("num=" + i);
        }
        System.gc();
    }


}

  测试jvm参数设置:

  

  测试结果:

  当创建第16个对象时,内存溢出

  

  可视化内存信息观察:

  

  分代回收机制理解:

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

2.2.案例二:线程的异常等待与异常运行

  测试代码如下:

package com.wfd360.outofmemory;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class TestThread {
    /**
     * 死循环演示
     *
     */
    public static void createBusyThread() {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("createBusyThread");
                while (true)
                    ;
            }
        }, "testBusyThread");
        thread.start();
    }

    /**
     * 线程锁等待
     *
     */
    public static void createLockThread(final Object lock) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("createLockThread");
                synchronized (lock) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }, "testLockThread");
        thread.start();
    }
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        br.readLine();
        createBusyThread();
        br.readLine();
        Object object = new Object();
        createLockThread(object);
    }
}

 

   线程监视图:

  

  线程dump:

   

  总结:通过线程可视化观察,“testLockThread”线程一直处于等待状态,那么我们就可以使用dump,导出堆栈信息,查看具体原因。

2.3.案例三:线程死锁实战演示

   测试代码:

package com.wfd360.thread;

public class DeadThread implements Runnable {
    //控制锁顺序
    private boolean lockFormer;
    //对象1
    private static Object o1 = new Object();
    //对象2
    private static Object o2 = new Object();

    DeadThread(boolean lockFormer) {
        this.lockFormer = lockFormer;
    }

    @Override
    public void run() {
        if (this.lockFormer) {
            synchronized (o1) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o2) {
                    System.out.println("1ok");
                }
            }
        } else {
            synchronized (o2) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (o1) {
                    System.out.println("2ok");
                }
            }
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 200; i++) {
            new Thread(new DeadThread(true)).start();
            new Thread(new DeadThread(false)).start();
        }
    }
}

   jvm内存监控观察:

  

  死锁检测:

  

2.3.1.死锁的构成基本条件

1、互斥条件:一份资源每次只能被一个进程或线程使用(在Java中一般体现为,一个对象锁只能被一个线程持有)

2、请求与保持条件:一个进程或线程在等待请求资源被释放时,不释放已占有资源

3、不可剥夺条件:一个进程或线程已经获得的资源不能被其他进程或线程强行剥夺

4、循环等待条件:形成一种循环等待的场景

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

  测试代码:

package com.wfd360.outofmemory;

import java.util.ArrayList;
import java.util.List;

/**
 * 演示堆内存溢出
 * 配置jvm参数
 * VM Args:
 * -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=f:/test/dump
 * 参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析,文件在项目中
 */
public class HeapOOM {
    static class OOMObject {
        public byte[] byt = new byte[1 * 1024*1024];
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();
        while (true) {
            list.add(new OOMObject());
        }
    }
}

 

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

    

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

    

    内存占比列表。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值