JVM 性能监控工具之可视化篇
第十五节:JVM 性能监控之可视化篇
前面我们已经讲了 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 的图了,希望大家可以理解。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107121534.png)
直接启动 JConsole,会弹出一个窗口,显示本机正在运行的 Java 程序,选择一个程序(比如说技术派的 28966),点击连接
即可。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107122523.png)
还可以进行远程链接,比如说对服务器上的 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占用率
四项信息的曲线图。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107125054.png)
内存监控
内存
的作用相当于可视化的 jstat 命令(上一节讲过了),用于监视 Java 堆的使用情况,可以更细化到 eden 区、suvivior 区、老年代的使用情况。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107125358.png)
为了更加清晰地查看内存变化,可以运行下面这段,然后连接:
/**
* 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 区的运行趋势,发现呈折线趋势增长。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107125932.png)
点击「执行 GC」之后,会发现老年代的柱状图会达到峰值状态,是因为执行 GC 之后,Eden 区的对象被回收,存活的对象被移动到老年代。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107130243.png)
线程监控
JConcole 还可以监控线程,相当于可视化的 jstack 命令(上一节讲过了)。
如下图,JConcole 显示了应用系统内的线程数量,左下方显示了程序中所有的线程。点击线程名称,就可以查看线程的栈信息。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107131040.png)
使用 JConsole 还可以快速定位死锁问题。上一篇我们曾写过一个死锁的例子,这里我们再来看一下。
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 线程面板下的 「检测到死锁
」按钮,将会看到线程的死锁信息。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107131533.png)
类加载情况
如下图,「类」面板显示了已经装载的类数量。在详细信息栏中,还显示了已经卸载的类的数量。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107131709.png)
VM 概要
在VM 概要
面板,JConsole 显示了当前应用程序的运行时环境,包括虚拟机类型、版本、堆信息以及虚拟机参数等。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107131747.png)
VisualVM
VisualVM(All-in-One Java Troubleshooting Tool)一款功能强大的运行监视和故障处理工具之一,在很长一段时间内,VisualVM 都是 Oracle 官方主推的故障处理工具。
集成了多个 JDK 命令行工具的功能,提供了一个友好的图形界面,非常适用于开发和生产环境。
VisualVM 安装插件
VisualVM 的安装非常简单,下载地址:https://visualvm.github.io
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107132705.png)
安装完成后打开的界面如下所示:
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107132947.png)
VisualVM 比 JConsole 强的不是一星半点,它不仅拥有更漂亮的身段,还支持插件功能。
点击tools
-> plugins
,在可用插件
里可以看到大量的插件,按需安装即可。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107133038.png)
VisualVM 中概述
、监视
、线程
与 JConsole 差别不大,这里就不在赘述。
生成、浏览堆转储快照
在 VisualVM 中生成堆转储快照文件有两种方式,可以执行下列任一操作:
①、在应用程序
面板中右键选择堆Dump
(也就是 Heap Dump)。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107133459.png)
②、在应用程序
面板中选择应用程序,在“监视”面板中单击堆Dump
。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107133533.png)
如果需要把堆转储快照保存文件后分享出去,可以在 heapdump 节点上右键选择“另存为”菜单,否则当 VisualVM 关闭时,生成的堆转储快照文件会被当作临时文件自动清理掉。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107133756.png)
分析程序性能
如果想对应用程序的 CPU 和内存情况进行分析,可以在「分析 profiler」面板中点击「CPU」或者「Memory」,然后 VisualVM 会记录这段时间中应用程序执行过的所有方法。
比如说 CPU 将会统计每个方法的执行次数、执行耗时。比如说内存将会统计每个方法的内存分配情况。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107134238.png)
注意点击开始后,回到应用程序进行操作。等要分析的操作执行结束后,点击“停止”按钮结束监控过程。
Java Mission Control
JMC 最初是 JRockit VM 中的诊断工具,但在 Oracle JDK7 Update 40 以后,就绑定到了 HotSpot VM 中。不过后来又被 Oracle 开源出来作为一个单独的产品。
GitHub 地址:https://github.com/openjdk/jmc
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107154540.png)
Oracle 官方下载比较慢,可以通过 jdk.java.net 下载。
解压后启动的界面如下所示:
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107154959.png)
MBean Server
点击本地进程的MBean服务器
:
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107155226.png)
MBean 是管理 Java 应用程序的一种标准方式,它是 Java 管理扩展(JMX)的一部分。MBean 代表可管理的 Java 对象,它们的属性和操作可以通过 JMX 进行访问。
仪表盘显示了 Java 堆的使用率,CPU 使用率和 Live Set+Fragmentation(Live Set 是指存活对象的大小,Fragmentation 是指碎片的大小)。
飞行记录器(Flight Recorder)
飞行记录器(JFR)是 JMC 提供的另一功能,通过记录应用程序在一段时间内的运行情况,再进行分析和展示,可以更进一步对应用程序的性能进行分析和诊断。
要使用 JFR,程序启动需要带以下参数:
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder
连接加了相关参数启动的程序,启动飞行记录,进行一分钟的性能记录:
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107160338.png)
记录结束后,JMC 会自动打开刚才的记录:
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107160555.png)
JFR 提供的数据质量通常也要比其他工具通过代理形式采样获得的更高。
以垃圾搜集为例,HotSpot 的 MBean 中一般有各个分代大小、收集次数、时间、占用率等数据,这些都属于“结果”类的信息,而 JFR 中还可以看到内存中这段时间分配了哪些对象、哪些对象被回收了,这些都属于“过程”类的信息。
我这里提供一些可供测试的代码,大家可以在本地跑一下,看看 JFR 的效果。
第一个:CPU 使用过高:
/**
* 消耗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();
}
第二个:内存使用过高:
/**
* 不断新增 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 仓库:
比如说通过「内存面板」可以看出 BigDecimal 对象占用了最多的内存。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107162040.png)
如果想进一步分析内存占用来源,可以切到线程页面,勾选三个复选框,可以在 memory 这里看到内存情况。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107162307.png)
还可以看到这里的 cpu_high_thread
在不断地计算浮点数,所以占用了较多的 CPU。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107162511.png)
死锁的情况也可以在这里看得到。
![](https://cdn.tobebetterjavaer.com/stutymore/view-tools-20240107162559.png)
第三方工具
以上三个都属于 Oracle 官方提供的性能监控工具,除此之外还有一些第三方的性能监控工具。
- 「MAT」
Java 堆内存分析工具。
- 「GChisto」
GC 日志分析工具。
- 「GCViewer」
GC
日志分析工具。
- 「JProfiler」
商用的性能分析利器。
- 「arthas」
阿里开源诊断工具。
- 「async-profiler」
Java 应用性能分析工具,开源、火焰图、跨平台。
小结
本篇我们介绍了一些可视化的性能监控工具,包括 JConsole、VisualVM、Java Mission Control 等,阿里的 Arthas 我们留到后面单独去讲。
参考链接:星球嘉宾三分恶 性能监控工具-可视化工具篇
GitHub 上标星 10000+ 的开源知识库《二哥的 Java 进阶之路》第一版 PDF 终于来了!包括Java基础语法、数组&字符串、OOP、集合框架、Java IO、异常处理、Java 新特性、网络编程、NIO、并发编程、JVM等等,共计 32 万余字,500+张手绘图,可以说是通俗易懂、风趣幽默……详情戳:太赞了,GitHub 上标星 10000+ 的 Java 教程
微信搜 沉默王二 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 222 即可免费领取。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/gongzhonghao.png)