JVM监控Jconsole

Jconsole是基于jmx协议也是jdk自带的可视化监视、管理工具。

启动JConsole

  • 点击JDK/bin 目录下面的jconsole.exe 即可启动
  • 然后会自动自动搜索本机运行的所有虚拟机进程。
  • 选择其中一个进程可开始进行监控

JConsole基本介绍

JConsole 基本包括以下基本功能:概述内存线程VM概要MBean

运行下面的程序、然后使用JConsole进行监控;注意设置虚拟机参数

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

/**
 *  设置虚拟机参数:
 *  -Xms100M -Xms100m -XX:+UseSerialGC -XX:+PrintGCDetails
 */
public class JConsoleTool {

    static class OOMObject {
        public byte[] placeholder = new byte[64 * 1024];
    }

    public static void fillHeap(int num) throws InterruptedException {
        Thread.sleep(20000); //先运行程序,在执行监控
        List list = new ArrayList();
        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);
        while(true){
            //让其一直运行着
        }

    }
}

 内存监控

内存页签相对于可视化的jstat 命令,用于监视受收集器管理的虚拟机内存。

JVM监控Jconsole_第1张图片

线程监控

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

下面三个方法分别等待控制台输入、死循环演示、线程锁等待演示

/**
  * 等待控制台输入
  * @throws IOException
  */
 public static  void waitRerouceConnection () throws IOException {
     BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
     br.readLine();
 }
/**
 * 线程死循环演示
 */
 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();
 }

线程死锁演示

这段代码开了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),结果出现大家都跑不下去的情景。

package com.jvm;

/**
 * 线程死锁验证
 */
public class JConsoleThreadLock {

    /**
     * 线程死锁等待演示
     */
    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();
        }
    }


}

结果描述:显示了线程Thread-53在等待一个被线程Thread-66持有Integer对象,而点击线程Thread-66则显示它也在等待一个Integer对象,被线程Thread-53持有,这样两个线程就互相卡住,都不存在等到锁释放的希望了 

转载来自: JConsole可视化工具介绍_uzong-CSDN博客_jconsole

你可能感兴趣的:(java)