Skip to content

整理自 沉默王二:原文。全文搬运仅供个人学习,请勿外传。

前面我们已经讲了 JVM 性能监控工具之命令行篇,本篇我们来介绍一些可视化的性能监控工具,包括 JConsole、VisualVM、Java Mission Control 等,阿里的 Arthas 我们留到后面单独去讲。

可视化工具比命令行工具强大的地方就在于这些工具提供了更直观、更易于理解的性能数据视图,肉眼看上去,脑子就能快速 get 到问题所在,那这篇就来带大家看看这些工具的强大之处。

JConsole ​

JConsole(Java Monitoring and Management Console),是一款基于 JMX(Java Manage-ment Extensions)的可视化监视管理工具。

JMX 的全称是 Java Management Extensions,翻译过来就是 Java 管理扩展,既是 Java 管理系统中的一个标准,一个规范,也是一个接口,一个框架。JConsole 就相当于是 JMX 的一个实现类。

JConsole 可以用来监视 Java 应用程序的运行状态,包括内存使用、线程状态、类加载、GC 等,还可以进行一些基本的性能分析。

JConsole 连接 Java 程序 ​

JConsole 程序位于%JAVA_HOME%bin 目录下,不过我当前的操作系统是 macOS,和 Windows 有一些不一样,我就不再刻意截 Windows 的图了,希望大家可以理解。

直接启动 JConsole,会弹出一个窗口,显示本机正在运行的 Java 程序,选择一个程序(比如说技术派的 28966),点击连接即可。

还可以进行远程链接,比如说对服务器上的 Java 程序进行监控,需要远程服务器上的 Java 程序在启动的时候加上以下这些参数:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=<PORT>
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
  • <PORT> 是您想要 JMX 代理监听的端口号,例如 9999。
  • authenticate=false 表示不需要身份验证来连接到 JMX(注意:这在生产环境中可能不安全)。
  • ssl=false 表示不需要使用 SSL 加密连接(同样,这在生产环境中可能不安全)。

Java 程序概况 ​

使用 JConsole 连接了一个本地程序,在概述可以看到 Java 程序的运行时概况,包括堆内存使用量、线程、类、CPU占用率四项信息的曲线图。

内存监控 ​

内存的作用相当于可视化的 jstat 命令(上一节讲过了),用于监视 Java 堆的使用情况,可以更细化到 eden 区、suvivior 区、老年代的使用情况。

为了更加清晰地查看内存变化,可以运行下面这段,然后连接:

java

/**
 * VM参数: -Xms100m -Xmx100m -XX:+UseSerialGC
 */
class JConcoleRAMMonitor {

    /***
     * 内存占位符对象,一个OOMObject大约占64KB
     */
    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(300);
            list.add(new OOMObject());
        }
        System.gc();
    }

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

这段代码的作用是以 64KB/50ms 的速度向 Java 堆中填充数据,一共填充 1000 次。

观察 Eden 区的运行趋势,发现呈折线趋势增长。

点击「执行 GC」之后,会发现老年代的柱状图会达到峰值状态,是因为执行 GC 之后,Eden 区的对象被回收,存活的对象被移动到老年代。

线程监控 ​

JConcole 还可以监控线程,相当于可视化的 jstack 命令(上一节讲过了)。

如下图,JConcole 显示了应用系统内的线程数量,左下方显示了程序中所有的线程。点击线程名称,就可以查看线程的栈信息。

使用 JConsole 还可以快速定位死锁问题。上一篇我们曾写过一个死锁的例子,这里我们再来看一下。

java
class DeadLockDemo {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (lock1) {
                System.out.println("线程1获取到了锁1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("线程1获取到了锁2");
                }
            }
        }).start();

        new Thread(() -> {
            synchronized (lock2) {
                System.out.println("线程2获取到了锁2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("线程2获取到了锁1");
                }
            }
        }).start();
    }
}

运行以上代码,点击 JConsole 线程面板下的 「检测到死锁」按钮,将会看到线程的死锁信息。

类加载情况 ​

如下图,「类」面板显示了已经装载的类数量。在详细信息栏中,还显示了已经卸载的类的数量。

VM 概要 ​

在VM 概要 面板,JConsole 显示了当前应用程序的运行时环境,包括虚拟机类型、版本、堆信息以及虚拟机参数等。

VisualVM ​

VisualVM(All-in-One Java Troubleshooting Tool)一款功能强大的运行监视和故障处理工具之一,在很长一段时间内,VisualVM 都是 Oracle 官方主推的故障处理工具。

集成了多个 JDK 命令行工具的功能,提供了一个友好的图形界面,非常适用于开发和生产环境。

VisualVM 安装插件 ​

VisualVM 的安装非常简单,下载地址:https://visualvm.github.io

安装完成后打开的界面如下所示:

VisualVM 比 JConsole 强的不是一星半点,它不仅拥有更漂亮的身段,还支持插件功能。

点击tools-> plugins,在可用插件里可以看到大量的插件,按需安装即可。

VisualVM 中概述、监视、线程与 JConsole 差别不大,这里就不在赘述。

生成、浏览堆转储快照 ​

在 VisualVM 中生成堆转储快照文件有两种方式,可以执行下列任一操作:

①、在应用程序面板中右键选择堆Dump(也就是 Heap Dump)。

②、在应用程序面板中选择应用程序,在“监视”面板中单击堆Dump。

如果需要把堆转储快照保存文件后分享出去,可以在 heapdump 节点上右键选择“另存为”菜单,否则当 VisualVM 关闭时,生成的堆转储快照文件会被当作临时文件自动清理掉。

分析程序性能 ​

如果想对应用程序的 CPU 和内存情况进行分析,可以在「分析 profiler」面板中点击「CPU」或者「Memory」,然后 VisualVM 会记录这段时间中应用程序执行过的所有方法。

比如说 CPU 将会统计每个方法的执行次数、执行耗时。比如说内存将会统计每个方法的内存分配情况。

注意点击开始后,回到应用程序进行操作。等要分析的操作执行结束后,点击“停止”按钮结束监控过程。

Java Mission Control ​

JMC 最初是 JRockit VM 中的诊断工具,但在 Oracle JDK7 Update 40 以后,就绑定到了 HotSpot VM 中。不过后来又被 Oracle 开源出来作为一个单独的产品。

GitHub 地址:https://github.com/openjdk/jmc

Oracle 官方下载比较慢,可以通过 jdk.java.net 下载。

https://jdk.java.net/jmc/8/

解压后启动的界面如下所示:

MBean Server ​

点击本地进程的MBean服务器:

MBean 是管理 Java 应用程序的一种标准方式,它是 Java 管理扩展(JMX)的一部分。MBean 代表可管理的 Java 对象,它们的属性和操作可以通过 JMX 进行访问。

仪表盘显示了 Java 堆的使用率,CPU 使用率和 Live Set+Fragmentation(Live Set 是指存活对象的大小,Fragmentation 是指碎片的大小)。

飞行记录器(Flight Recorder) ​

飞行记录器(JFR)是 JMC 提供的另一功能,通过记录应用程序在一段时间内的运行情况,再进行分析和展示,可以更进一步对应用程序的性能进行分析和诊断。

要使用 JFR,程序启动需要带以下参数:

-XX:+UnlockCommercialFeatures  -XX:+FlightRecorder

连接加了相关参数启动的程序,启动飞行记录,进行一分钟的性能记录:

记录结束后,JMC 会自动打开刚才的记录:

JFR 提供的数据质量通常也要比其他工具通过代理形式采样获得的更高。

以垃圾搜集为例,HotSpot 的 MBean 中一般有各个分代大小、收集次数、时间、占用率等数据,这些都属于“结果”类的信息,而 JFR 中还可以看到内存中这段时间分配了哪些对象、哪些对象被回收了,这些都属于“过程”类的信息。

我这里提供一些可供测试的代码,大家可以在本地跑一下,看看 JFR 的效果。

第一个:CPU 使用过高:

java
/**
 * 消耗CPU的线程
 * 不断循环进行浮点运算
 */
private static void cpuHigh() {
    Thread thread = new Thread(() -> {
        Thread.currentThread().setName("cpu_high_thread");
        while (true){
            double pi = 0;
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                pi += Math.pow(-1, i) / (2 * i + 1);
            }
            System.out.println("Pi: " + pi * 4);
        }
    });
    thread.start();
}

第二个:内存使用过高:

java
/**
 * 不断新增 BigDecimal 信息到 list
 */
private static void allocate() {
    new Thread(()->{
        Thread.currentThread().setName("memory_allocate_thread");
        List<BigDecimal> list = new ArrayList<>();
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            list.add(new BigDecimal(i));
        }
    }).start();
}

完整示例可以参考这个 GitHub 仓库:

https://github.com/itwanger/paicoding/blob/main/paicoding-web/src/test/java/com/github/paicoding/forum/test/javabetter/jvm/HotCode.java

比如说通过「内存面板」可以看出 BigDecimal 对象占用了最多的内存。

如果想进一步分析内存占用来源,可以切到线程页面,勾选三个复选框,可以在 memory 这里看到内存情况。

还可以看到这里的 cpu_high_thread 在不断地计算浮点数,所以占用了较多的 CPU。

死锁的情况也可以在这里看得到。

第三方工具 ​

以上三个都属于 Oracle 官方提供的性能监控工具,除此之外还有一些第三方的性能监控工具。

  • ​「MAT」​

Java 堆内存分析工具。

  • ​「GChisto」​

GC 日志分析工具。

  • ​「GCViewer」​

GC 日志分析工具。

  • ​「JProfiler」​

商用的性能分析利器。

  • ​「arthas」​

阿里开源诊断工具。

  • ​「async-profiler」​

Java 应用性能分析工具,开源、火焰图、跨平台。

小结 ​

本篇我们介绍了一些可视化的性能监控工具,包括 JConsole、VisualVM、Java Mission Control 等,阿里的 Arthas 我们留到后面单独去讲。

参考链接:星球嘉宾三分恶 性能监控工具-可视化工具篇


GitHub 上标星 17000+ 的开源知识库《二哥的 Java 进阶之路》第一版 PDF 终于来了!包括Java基础语法、数组&字符串、OOP、集合框架、Java IO、异常处理、Java 新特性、网络编程、NIO、并发编程、JVM等等,共计 32 万余字,500+张手绘图,可以说是通俗易懂、风趣幽默……详情戳:太赞了,GitHub 上标星 17000+ 的 Java 教程

微信搜 沉默王二 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 222 即可免费领取。

本文整理自沉默王二 后端八股的公开内容,仅供个人学习使用

本站仅供个人学习使用,请勿外传