深入理解java虚拟机 摘要(八)--JDK的可视化工具

深入理解java虚拟机 摘要


二、虚拟机性能监控与故障处理工具


1. JDK的可视化工具

(一)JConsole:Java监视与管理控制台

JConsole(Java Monitoring and Management Console)是一种基于JMX的可视化监视、管理工具。它管理部分的功能是针对JMX MBean进行管理,由于MBean可以使用代码、中间件服务器的管理控制台或者所有符合JMX规范的软件进行访问
1. 启动JConsole
通过JDK/bin目录下的“jconsole.exe”启动JConsole后,将自动搜索出本机运行的所有虚拟机进程,不需要用户自己再使用jps来查询了。双击选择其中一个进程即可开始监控,也可以使用下面的“远程进程”功能来连接远程服务器,对远程虚拟机进行监控。
这里写图片描述

  1. 内存监控
    “内存”页签相当于可视化的jstat命令,用于监视受收集器管理的虚拟机内存(Java堆和永久代)的变化趋势。我们通过运行代码来体验一下它的监视功能。运行时设置的虚拟机参数为:-Xms100m-Xmx100m-XX:+UseSerialGC,这段代码的作用是以10KB/50毫秒的速度往Java堆中填充数据,一共填充1000次,使用JConsole的“内存”页签进行监视,观察曲线和柱状指示图的变化

代码示例:

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

/**
 * 堆内存增长模拟
 *
 * -Xms100m -Xmx100m -XX:+UseSerialGC
 * @author wp
 * @create 2018-02-26 14:31
 *
 *  输入:
 *  begin 开启任务
 *  exit 退出
 **/
public class HeapIncrease {
    public static void fillHeap(Integer num) {
        List<OomObject> list = new ArrayList<OomObject>();
        for (int i = 0; i < num; i++) {
            try {
                Thread.sleep(50);
                list.add(new OomObject());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String args[]){
        Scanner scanner = new Scanner(System.in);
        while (true){
            String flag = scanner.next();
            if(flag.equals("begin")){
                fillHeap(1000);
                System.out.println("over!!!");
            }else if(flag.equals("exit")){
                System.out.println("over!!!");
                break;
            }
        }
    }
}
class OomObject {
    Byte[] bytes = new Byte[10 * 1024];
}
  1. 线程监控
    “线程”页签的功能相当于可视化的jstack命令,遇到线程停顿时可以使用这个页签进行监控分析。

代码示例:

/**
 * 线程异常演示
 *
 * @author wp
 * @create 2018-03-01 15:51
 *  输入:
 *  busyThread 创建一条死循环线程
 *  lockThread 创建一条锁等待线程
 *  deadLockThread 创建200条线程 以产生死锁
 *  exit 退出
 **/
public class ThreadErr {
    /**
     * 线程死循环演示
     */
    public static void createBusyThread(String name) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {

                }
            }
        }, name);
        thread.start();
    }

    /**
     * 线程锁等待演示
     */
    public static void createLockThread(final Object lock,String name) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, name);
        thread.start();
    }

    /**
     *线程死锁等待演示
     */
    static class SynAddRunalbe implements Runnable{
        int a,b;
        public SynAddRunalbe(int a,int b){
            this.a=a;
            this.b=b;
        }
        @Override
        public void run(){
            synchronized(Integer.valueOf(a)){
                synchronized(Integer.valueOf(b)){
                    System.out.println(a+b);
                }
            }
        }
    }
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        int i =1;
        out:
        while (true){
            String command = scanner.nextLine();
            switch (command){
                case "busyThread":
                    createBusyThread("busyThread -"+i);
                    break;
                case "lockThread":
                    createLockThread(new Object(),"lockThread -" + i);
                    break;
                case "deadLockThread":
                    for (int j = 0; j < 100; j++) {
                        new Thread(new SynAddRunalbe(1, 2),"deadLockThread -"+i).start();
                        new Thread(new SynAddRunalbe(2,1),"deadLockThread -"+i).start();
                    }
                    break;
                case "exit":
                    break out;
            }
            i++;
        }

    }
}

死锁产生解释:
这段代码开了200个线程去分别计算1+2以及2+1的值,其实for循环是可省略的,两个线程也可能会导致死锁,不过那样概率太小,需要尝试运行很多次才能看到效果。一般的话,带for循环的版本最多运行2~3次就会遇到线程死锁,程序无法结束。造成死锁的原因是
Integer.valueOf()方法基于减少对象创建次数和节省内存的考虑,[-128,127]之间的数字会被缓存 [3] ,当valueOf()方法传入参数在这个范围之内,将直接返回缓存中的对象。也就是说,代码中调用了200次Integer.valueOf()方法一共就只返回了两个不同的对象。假如在某个线程的两个synchronized块之间发生了一次线程切换,那就会出现线程A等着被线程B持有的Integer.valueOf(1),线程B又等着被线程A持有的Integer.valueOf(2),结果出现大家都跑不下去的情景。

PS:运行结果不多做解释 , 大家自行观察

(二)VisualVM:多合一故障处理工具

VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,并且可以预见在未来一段时间内都是官方主力发展的虚拟机故障处理工具。官方在VisualVM的软件说明中写上了“All-in-One”的描述字样,预示着它除了运行监视、故障处理外,还提供了很多其他方面的功能。
位置:位于jdk,bin目录下的 jvisualvm.exe
官网:https://visualvm.github.io/index.html
1. 插件
插件可以进行手工安装,在相关网站上下载*.nbm包后,点击“工具”→“插件”→“已下载”菜单,然后在弹出的对话框中指定nbm包路径便可进行安装,插件安装后存放在
JDK_HOME/lib/visualvm/visualvm中。不过手工安装并不常用,使用VisualVM的自动安装功能已经可以找到大多数所需的插件,在有网络连接的环境下,点击“工具”→“插件菜单”,大家可以根据自己的工作需要和兴趣选择合适的插件,然后点击安装按钮。
2. 生成、浏览堆转储快照
3. 分析程序性能
在Profiler页签中,VisualVM提供了程序运行期间方法级的CPU执行时间分析以及内存分析,做Profiling分析肯定会对程序运行性能有比较大的影响,所以一般不在生产环境中使用这项功能。要开始分析,先选择“CPU”和“内存”按钮中的一个,然后切换到应用程序中对程序进行操作,VisualVM会记录到这段时间中应用程序执行过的方法。如果是CPU分析,将会统计每个方法的执行次数、执行耗时;如果是内存分析,则会统计每个方法关联的对象数以及这些对象所占的空间。分析结束后,点击“停止”按钮结束监控过程
4. BTrace动态日志跟踪
BTrace 是一个很“有趣”的VisualVM插件,本身也是可以独立运行的程序。它的作用是在不停止目标程序运行的前提下,通过HotSpot虚拟机的HotSwap技术动态加入原本并不存在的调试代码。
在VisualVM中安装了BTrace插件后,在应用程序面板中右键点击要调试的程序,会出现“Trace Application……”菜单,点击将进入BTrace面板。
BTrace的用法有许多,打印调用堆栈、参数、返回值只是最基本的应用,在它的网站上有使用BTrace进行性能监视、定位连接泄漏和内存泄漏、解决多线程竞争问题等例子

为什么要学JVM1、一切JAVA代码都运行在JVM之上,只有深入理解虚拟机才能写出更强大的代码,解决更深层次的问题。2、JVM是迈向高级工程师、架构师的必备技能,也是高薪、高职位的不二选择。3、同时,JVM又是各大软件公司笔试、面试的重中之重,据统计,头部的30家互利网公司,均将JVM作为笔试面试的内容之一。4、JVM内容庞大、并且复杂难学,通过视频学习是最快速的学习手段。课程介绍本课程包含11个大章节,总计102课时,无论是笔试、面试,还是日常工作,可以让您游刃有余。第1章 基础入门,从JVM是什么开始讲起,理解JDK、JRE、JVM的关系,java的编译流程和执行流程,让您轻松入门。第2章 字节码文件,深入剖析字节码文件的全部组成结构,以及javap和jbe可视化反解析工具的使用。第3章 类的加载、解释、编译,本章节带你深入理解类加载器的分类、范围、双亲委托策略,自己手写类加载器,理解字节码解释器、即时编译器、混合模式、热点代码检测、分层编译等核心知识。第4章 内存模型,本章节涵盖JVM内存模型的全部内容,程序计数器、虚拟机栈、本地方法栈、方法区、永久代、元空间等全部内容。第5章 对象模型,本章节带你深入理解对象的创建过程、内存分配的方法、让你不再稀里糊涂。第6章 GC基础,本章节是垃圾回收的入门章节,带你了解GC回收的标准是什么,什么是可达性分析、安全点、安全区,四种引用类型的使用和区别等等。第7章 GC算法与收集器,本章节是垃圾回收的重点,掌握各种垃圾回收算法,分代收集策略,7种垃圾回收器的原理和使用,垃圾回收器的组合及分代收集等。第8章 GC日志详解,各种垃圾回收器的日志都是不同的,怎么样读懂各种垃圾回收日志就是本章节的内容。第9章 性能监控与故障排除,本章节实战学习jcmd、jmx、jconsul、jvisualvm、JMC、jps、jstatd、jmap、jstack、jinfo、jprofile、jhat总计12种性能监控和故障排查工具的使用。第10章 阿里巴巴Arthas在线诊断工具,这是一个特别小惊喜,教您怎样使用当前最火热的arthas调优工具,在线诊断各种JVM问题。第11章 故障排除,本章会使用实际案例讲解单点故障、高并发和垃圾回收导致的CPU过高的问题,怎样排查和解决它们。课程资料课程附带配套项目源码2个159页高清PDF理论篇课件1份89页高清PDF实战篇课件1份Unsafe源码PDF课件1份class_stats字段说明PDF文件1份jcmd Thread.print解析说明文件1份JProfiler内存工具说明文件1份字节码可视化解析工具1份GC日志可视化工具1份命令行工具cmder 1份学习方法理论篇部分推荐每天学习2课时,可以在公交地铁上用手机进行学习。实战篇部分推荐对照视频,使用配套源码,一边练习一遍学习。课程内容较多,不要一次性学太多,而是要循序渐进,坚持学习。      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值