一、简介

Java VisualVM 是一个直观的图形用户界面,基于Java 的应用程序,在给定的 Java 虚拟机(JVM)上运行时提供有关它们的详细信息。Java VisualVM 之所以这样命名,是因为Java VisualVM 可视地提供了有关JVM软件的信息。

Java VisualVM 将多个监视、故障排除和性能分析实用程序组合到一个工具中。 例如,独立工具 jmap,jinfo,jstat 和 jstack 提供的大多数功能已集成到 Java VisualVM 中。 可以将其他功能(例如 JConsole 工具提供的某些功能)添加为可选插件。

JVisualVM 使用简单,几乎0配置,功能还是比较丰富的,几乎囊括了其它JDK自带命令的所有功能。

  • 内存信息
  • 线程信息
  • Dump堆(本地进程)
  • Dump线程(本地进程)
  • 打开堆Dump。堆Dump可以用jmap来生成。
  • 打开线程Dump
  • 生成应用快照(包含内存信息、线程信息等等)
  • 性能分析。 CPU分析(各个方法调用时间,检查哪些方法耗时多),内存分析(各类对象占用的内存,检查哪些类占用内存多)

二、使用

1、找到 jvisualvm, 在jdk安装目录找到 jvisualvm.exe,${JDK_HOME}\bin\jvisualvm.exe

java VisualVM 如何debug java visualvm使用_Java

2、打开该工具,通过菜单“工具”—>“插件”开发以下对话框

java VisualVM 如何debug java visualvm使用_ide_02


3、找到对应的 Java VisualVM 插件中心的网址,我这里是 JDK8u91,所以在我箭头的这个范围

java VisualVM 如何debug java visualvm使用_Java_03


故插件中心的网址是: https://visualvm.github.io/archive/uc/8u40/updates.xml.gz

java VisualVM 如何debug java visualvm使用_ide_04

把地址填进去就可以下载插件了

java VisualVM 如何debug java visualvm使用_ide_05


这里用两个常用的插件就行,其他的插件看你自己按需下载。

java VisualVM 如何debug java visualvm使用_Java_06

4、我用的 IDEA 启动了一个程序
5、JVisualVM 的详细信息会出现在详细面板上

java VisualVM 如何debug java visualvm使用_Java_07

java VisualVM 如何debug java visualvm使用_ide_08

java VisualVM 如何debug java visualvm使用_System_09

java VisualVM 如何debug java visualvm使用_ide_10


6、可以看具体的线程快照信息

java VisualVM 如何debug java visualvm使用_ide_11


java VisualVM 如何debug java visualvm使用_ide_12


右键,保存线程快照信息。

收集线程快照信息主要是为了监控是否有出现死锁的情况:

刚好我这里有个例子:

package com.concurrent.deadLock;

/**
 * @author riemann
 * @date 2019/08/14 22:44
 */
public class ThreadTest {

    public static void main(String[] args) {
        new Thread(new Thread1()).start();
        new Thread(new Thread2()).start();
        // new Thread(new Thread3()).start();
    }

}

class ThreadResource {
    public static Object resource1 = new Object();
    public static Object resource2 = new Object();
}

class Thread1 implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println("Thread1 is running");
            synchronized (ThreadResource.resource1) {
                System.out.println("Thread1 lock resource1");
                Thread.sleep(2000);//休眠2s等待线程2锁定资源2
                synchronized (ThreadResource.resource2) {
                    System.out.println("Thread1 lock resource2");
                }
                System.out.println("Thread1 release resource2");
            }
            System.out.println("Thread1 release resource1");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread1 is stop");
    }
}

class Thread2 implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println("Thread2 is running");
            synchronized (ThreadResource.resource2) {
                System.out.println("Thread2 lock resource2");
                Thread.sleep(2000);//休眠2s等待线程1锁定资源1
                synchronized (ThreadResource.resource1) {
                    System.out.println("Thread2 lock resource1");
                }
                System.out.println("Thread2 release resource1");
            }
            System.out.println("Thread2 release resource2");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread2 is stop");
    }
}

class Thread3 implements Runnable {

    @Override
    public void run() {
        try {
            System.out.println("Thread is running");
            if (ThreadResource.resource1.hashCode() > ThreadResource.resource2.hashCode()) {
                //先锁定resource1
                synchronized (ThreadResource.resource1) {
                    System.out.println("Thread lock resource1");
                    Thread.sleep(2000);
                    synchronized (ThreadResource.resource2)
                    {
                        System.out.println("Thread lock resource2");
                    }
                    System.out.println("Thread release resource2");
                }
                System.out.println("Thread release resource1");
            } else {
                //先锁定resource2
                synchronized (ThreadResource.resource2)
                {
                    System.out.println("Thread lock resource2");
                    Thread.sleep(2000);
                    synchronized (ThreadResource.resource1)
                    {
                        System.out.println("Thread lock resource1");
                    }
                    System.out.println("Thread release resource1");
                }
                System.out.println("Thread release resource2");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread1 is stop");
    }
}

输出结果:

Thread1 is running
Thread1 lock resource1
Thread2 is running
Thread2 lock resource2

观察收集到快照信息,拉到最后看看,如图,就是有出现死锁

java VisualVM 如何debug java visualvm使用_ide_13

两个线程都在互相等待对方释放锁,造成死锁。

7、拿堆栈快照信息

拿堆栈快照信息,如图,选择监控->堆Dump

java VisualVM 如何debug java visualvm使用_Java_14


java VisualVM 如何debug java visualvm使用_ide_15


同样右键->保存,保存堆栈快照信息。