JConsole(Java Monitoring and Management Console)是一种基于JMX的可视化监视、管理工具。他管理部分的功能是针对JMX MBean进行管理,由于MBean可以使用代码、中间件服务器的管理控制台或者所有符合JMX规范的软件进行访问,这里着重介绍JConsole监控部分的功能。

启动JConsole

通过JDK/bin目录下的“jconsole.exe”启动JConsole后,将自动搜索出本机运行的所有虚拟机进程,不需要用户自己再使用jps来查询了,如下图所示。双击选择其中一个进程即可开始监听,也可以使用下面的“远程进程”功能来连接远程服务器,对远程虚拟机进行监控。

从上图可以看出,该机器现在运行了Eclipse、JConsole和MonitoringTest三个本地虚拟机进程,其中MonitoringTest就是准备的“反面教材”代码之一。双击他进入JConsole主界面,可以看到主界面里共包括“概述”、“内存”、“线程”、“类”、“VM摘要”、“MBean”6个页签,如下图所示。

“概述”页签显示的是整个虚拟机运行数据的概览,其中包括“堆内存使用情况”、“线程”、“类”、“CPU使用情况”4种信息的曲线图,这些曲线图是后面“内存”、“线程”、“类”页签的信息汇总,具体内容将在后面介绍。

内存监控

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

/**
 * 内存占位符对象,一个OOMObject大约占64K
 */
static class OOMObject {
    public byte[] placeholder = new byte[64 * 1024];
}

public static void fillHeap(int num) throws InterruptedException {
    List<OOMObject> list = new ArrayList<OOMObject>();
    for (int i = 0; i < num; i++) {
        // 稍作延时,令监视曲线的变化更加明显
        Thread.sleep(50);
        list.add(new OOMObject());
    }
    System.gc();
}

public static void main(String[] args) throws Exception {
    fillHeap(1000);
}

程序运行后,在“内存”页签中可以看到内存池Eden区的运行趋势呈现折线状,如下图所示。而监视范围扩大至整个堆后,会发现曲线是一条向上增长的平滑曲线。并且从柱状图可以看出,在1000次循环执行结束,运行了System.gc()后,虽然整个新生代Eden和Survivor区都基本被清空了,但是代表老年代的柱状图仍然保持峰值状态,说明被填充进堆中的数据在System.gc()方法执行之后仍然存活。现提两个小问题供思考。

  • 虚拟机启动参数只限制了Java堆为100MB,没有指定-Xmn参数,能否从监控图中估计出新生代有多大?

下图显示Eden空间为27 328KB,因为没有设置-XX : SurvivorRadio参数,所以Eden与Survivor空间比例为默认值8:1,整个新生代空间大约为27 328KB*125%=34 160KB。

  • 为何执行了System.gc()之后,下图中代表老年代的柱状图仍然显示峰值状态,代码需要如何调整才能让System.gc()回收掉填充到堆中的对象?

执行完System.gc()之后,空间未能回收是因为List<OOMObject> list对象仍然存活,fillHeap()方法仍然没有退出,因此list对象在System.gc()执行时仍然处于作用域之内。如果把System.gc()移动到fillHeap()方法外调用就可以回收掉全部内存。

线程监控

如果上面的“内存”页签相当于可视化的jstat命令的话,“线程”页签的功能相当于可视化的jstack命令,遇到线程停顿时可以使用这个页签进行监控分析。线程长时间停顿的主要原因主要有:等待外部资源(数据库连接、网络资源、设备资源等)、死循环、锁等待(活锁和死锁)。同构下面代码分别演示一下这几种情况。

/**
 * 线程死循环演示
 */
public static void createBusyThread() {
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        while (true)   // 第41行
            ;
    }
}, "testBusyThread");
thread.start();
}

/**
 * 线程锁等待演示
 */
public static void createLockThread(final Object lock) {
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        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 obj = new Object();
    createLockThread(obj);
}

程序运行后,首先在“线程”页签中选择main线程,如下图所示。堆栈追踪显示BufferedReader在readBytes方法中等待System.in的键盘输入,这时线程为Runnable状态,Runnable状态的线程会被分配运行时间,但readBytes方法检查到流没有更新时会立刻归还执行令牌,这种等待只消耗很小的CPU资源。

接着监控testBusyThread线程,如下图所示,testBusyThread线程一直在执行空循环,从堆栈追踪中看到一直在MonitoringTest.java代码的41行停留,41行为:while(true)。这时候线程为Runnable状态,而且没有归还线程执行令牌的动作,会在空循环上用尽全部执行时间直到线程切换,这种等待会消耗较多的CPU资源。

下图显示testLockThread线程在等待着lock对象的notify或notifyAll方法的出现,线程这时候处于WAITING状态,在被唤醒前不会被分配执行时间。

testLockThread线程正在处于正常的活锁等待,只要lock对象的notify()或notifyAll()方法被调用,这个线程便能激活以继续执行。下面代码演示了一个无法再被激活的死锁等待。

/**
 * 线程死锁等待演示
 */
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) {
    for (int i = 0; i < 100; i++) {
        new Thread(new SynAddRunalbe(1, 2)).start();
        new Thread(new SynAddRunalbe(2, 1)).start();
    }
}

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

出现线程死锁之后,点击JConsole线程面板的“检测到死锁”按钮,将出现一个新的“死锁”页签,如下图所示。

上图中很清晰的显示了线程Thread-43在等待一个被线程Thread-12持有Integer对象,而点击线程Thread-12则显示他也在等待一个Integer对象,被线程Thread-43持有,这样两个线程就互相卡住,都不存在等到锁释放的希望了。

JDK的可视化工具——Java监视与管理控制台(JConsole)。相关推荐

  1. JDK的可视化工具系列 (四) JConsole、VisualVM

    JConsole: Java监视与管理控制台 代码清单1: import java.util.*;public class JConsoleDemo {static class OOMObject { ...

  2. Java监视和管理控制台

    Java监视和管理控制台 说明:通过java监视器和管理控制台可全面了解某java进程的内存.cpu.线程等的使用情况. 1.执行命令,唤起java监视和管理控制台 # 在java环境的bin目录下, ...

  3. JVM-11虚拟机性能监控与故障处理工具之【JDK的可视化工具-JConsole】

    文章目录 思维导图 概述 JConsole: Java监视与管理平台 启动jconsole 内存监控示例 VM ARGS 代码 JConsole监控展示及说明 扩展问题 没有指定-Xmn,如何确定新生 ...

  4. JConsole:Java监视与管理控制台

    JConsole是一款基于JMX的可视化监视.管理工具.它的主要功能是通过JMX的MBean对系统进 行信息收集和参数动态调整. 点击JDK/bin 目录下面的jconsole.exe 即可启动 内存 ...

  5. JVM-12虚拟机性能监控与故障处理工具之【JDK的可视化工具-VisualVM】

    文章目录 思维导图 概述 生成.浏览堆转储快照 分析程序性能 BTrace 思维导图 概述 Visual VM (All-in-One Java Troubleshooting Tool)是目前为止随 ...

  6. Java 自带性能监控工具:监视和管理控制台jconsole的使用

    关于JConsole工具的使用请参见:http://blog.csdn.net/defonds/article/details/45064297

  7. Java 自带性能监控工具:监视和管理控制台 jconsole 的使用

    添加链接描述 tomcat内存溢出问题记录 Java程序堆内存使用率很高的一般分析思路

  8. java 虚拟机(jvm)-06-JVM jdk 自带工具 jstack jconsole jvisualvm jmap jinfo

    jdk 自带工具 在 java 安装目录 bin 下. 你可以看到对应的信息,这里有很多 java 为我们提供的工具. $ ls appletviewer.exe* java-rmi.exe* jav ...

  9. Java内存泄露和内存溢出、JVM命令行工具、.JDK可视化工具、Java Class文件

    1.Java内存泄露和内存溢出对比 1.1 Java 内存泄露 内存泄露是指一个不再被程序使用的对象或变量还在内存中占用空间. 1.1.1判断内存空间是否符合垃圾回收的标准 在Java语言中,判断一个 ...

  10. 深入理解JAVA虚拟机学习笔记11——JDK可视化工具-VisualVM以及案例分析

    VisualVM:多合一故障处理工具,功能比较全面的一个工具,与其它的检测工具相比,对实际性能影响很小,并且还具备安装插件功能.这个工具和前面介绍的JConsole工具有很多类似的功能,但是比JCon ...

最新文章

  1. 基于图像的三维模型重建——相机模型与对极几何
  2. SQL Server 2008空间数据应用系列六:基于SQLCRL的空间数据可编程性
  3. java基础 关于转换流
  4. Android笔记-Xposed的使用(Hook登录函数获取用户名密码)
  5. html中擦窗效果,纯CSS写的小雨打在窗户上效果
  6. 关于c语言的基本知识,第二章_关于C语言的基本知识.ppt
  7. Android TextView文字横向自动滚动(跑马灯)
  8. Java JSP EL
  9. 【转载】web.xml中的classpath和classpath*
  10. No module named sqlite3解决
  11. matlab保存矩阵为txt,matlab保存矩阵成txt
  12. Win10锁屏壁纸位置在哪?默认锁屏壁纸怎么提取
  13. 相对湿度与绝对湿度换算
  14. 全民一起玩python提高篇,全民一起玩Python 基础篇+提高篇+笔记2019年
  15. 要不是这些沙雕插件,我早就被公司开除了。
  16. Gate用户手册(二)怎样运行Gate以及可视化
  17. 配置接口IP地址并通过静态路由、默认路由配置实现全网互通!
  18. [生存志] 第89节 太公阴符天人之道
  19. 在线制作动态显示折线图
  20. Transaction silently rolled back because it has been marked as rollback-only

热门文章

  1. mysql5.6 relay.info_Relay log 导致复制启动失败
  2. 网易免费邮箱服务器,网易免费邮箱重新免费开放 POP3/SMTP 服务
  3. java 代码块 构造函数_Java学习笔记之------构造函数,静态关键字,静态代码块,构造代...
  4. android开发界面设计工具,21个免费的UI界面设计工具、资源及网站
  5. 53Java模拟器,515最好的java模拟器
  6. 安卓java模拟器怎么用_安卓java模拟器(安卓手机如何玩JAVA游戏以及JAVA软件的方法)...
  7. 富爸爸系列:富爸爸穷爸爸实践
  8. vscode配置maven,settings.json文件
  9. 计算机网络保密承诺书,保密承诺书集合5篇
  10. 2021湖北技能高考成绩时间查询,2020湖北技能高考成绩查询时间