一、简介
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
2、打开该工具,通过菜单“工具”—>“插件”开发以下对话框
3、找到对应的 Java VisualVM 插件中心的网址,我这里是 JDK8u91,所以在我箭头的这个范围
故插件中心的网址是: https://visualvm.github.io/archive/uc/8u40/updates.xml.gz
把地址填进去就可以下载插件了
这里用两个常用的插件就行,其他的插件看你自己按需下载。
4、我用的 IDEA 启动了一个程序
5、JVisualVM 的详细信息会出现在详细面板上
6、可以看具体的线程快照信息
右键,保存线程快照信息。
收集线程快照信息主要是为了监控是否有出现死锁的情况:
刚好我这里有个例子:
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
观察收集到快照信息,拉到最后看看,如图,就是有出现死锁
两个线程都在互相等待对方释放锁,造成死锁。
7、拿堆栈快照信息
拿堆栈快照信息,如图,选择监控->堆Dump
同样右键->保存,保存堆栈快照信息。