03-JVM监控及诊断工具-GUI篇
JVM监控及诊断工具-GUI篇
工具概述
使用上一章命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但它们存在下列局限:
1.无法获取方法级别的分析数据,如方法间的调用关系、各方法的调用次数和调用时间等(这对定位应用性能瓶颈至关重要)。
2.要求用户登录到目标 Java 应用所在的宿主机上,使用起来不是很方便。
3.分析数据通过终端输出,结果展示不够直观。
为此,JDK提供了一些内存泄漏的分析工具,如jconsole,jvisualvm等,用于辅助开发人员定位问题,但是这些工具很多时候并不足以满足快速定位的需求。所以这里我们介绍的工具相对多一些、丰富一些。
图形化综合诊断工具
- JDK自带的工具
- jconsole:JDK 自带的可视化监控工具。查看 Java 应用程序的运行概况、监控堆信息、永久区(或元空间)使用情况、类加载情况等
- 位置:
<JAVA_HOME>\bin\jconsole.exe
- 位置:
- Visual VM:Visual VM 是一个工具,它提供了一个可视界面,用于查看 Java 虚拟机上运行的基于 Java 技术的应用程序的详细信息。
- 官网:https://visualvm.github.io/ ,默认情况下,JDK 不再带这个工具,需要自行下载
- JMC:Java Mission Control,内置 Java Flight Recorder。能够以极低的性能开销收集Java虚拟机的性能数据。
- jconsole:JDK 自带的可视化监控工具。查看 Java 应用程序的运行概况、监控堆信息、永久区(或元空间)使用情况、类加载情况等
- 第三方工具
- MAT:MAT(Memory Analyzer Tool)是基于 Eclipse 的内存分析工具,是一个快速、功能丰富的 Java heap 分析工具,它可以帮助我们查找内存泄漏和减少内存消耗
- Eclipse 的插件形式安装
- JProfiler:商业软件,需要付费。功能强大。
- MAT:MAT(Memory Analyzer Tool)是基于 Eclipse 的内存分析工具,是一个快速、功能丰富的 Java heap 分析工具,它可以帮助我们查找内存泄漏和减少内存消耗
JConsole
jconsole
:从 Java 5 开始,在 JDK 中自带的 Java 监控和管理控制台。用于对 JVM 中内存、线程和类等的监控,是一个基于 JMX(java management extensions) 的 GUI 性能监控工具。
官方文档:https://docs.oracle.com/javase/7/docs/technotes/guides/management/jconsole.html
启动
两种启动方式:
- 直接单击
jconsole.exe
,仅适用于 Windows - 命令行窗口中输入
jconsole
命令
启动界面如下:
JConsole启动界面
需要选择一个要监控的进程。
界面如下:
三种启动方式
- Local:使用 JConsole 连接一个正在本地系统运行的 JVM,并且执行程序的和运行 JConsole 的需要是同一个用户。JConsole 使用文件系统的授权通过 RMI 连接起链接到平台的 MBean 的服务器上。这种从本地连接的监控能力只有 Sun 的 JDK 具有。
- Remote:使用下面的 URL 通过 RMI 连接器连接到一个 JMX 代理,
service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi
。JConsole 为建立连接,需要在环境变量中设置mx.remote.credentials
来指定用户名和密码,从而进行授权。 - Advanced:使用一个特殊的 URL 连接 JMX 代理。一般情况使用自己定制的连接器而不是 RMI 提供的连接器来连接 JMX 代理,或者是一个使用 JDK1.4 的实现了 JMX 和 JMX Remote 的应用
Visual VM
- Visual VM是一个功能强大的多合一故障诊断和性能监控的可视化工具。
- 它集成了多个JDK命令行工具,使用Visual VM可用于显示虚拟机进程及进程的配置和环境信息(jps,jinfo),监视应用程序的CPU、GC、堆、方法区及线程的信息(jstat、jstack)等,甚至代替JConsole。
- 在JDK 6 Update 7以后,Visual VM便作为JDK的一部分发布(VisualVM 在JDK/bin目录下)即:它完全免费。
- 此外,Visual VM也可以作为独立的软件安装:官方地址:https://visualvm.github.io/index.html
Visual VM
插件的安装
IDEA 安装 VisualVM Launcher 插件
“File” →→ “Settings” →→ “Plugins” 打开插件安装界面。
在市场(Marketplace)中搜索 “VisualVM Launcher”
插件安装好之后,重启IDEA,然后再打开 “Settings” 配置界面,找到 “VisualVM Launcher”,配置VisualVM的路径和JDK,如下:
连接方式
1. 在IDEA中通过插件启动
两种启动方式,一种是正常启动,一种是DEBUG启动。
也可启动应用后通过,左侧的 “Start VisualVM” 来启动。
启动后的界面如下:
2. 本地连接
进入到VisualVM安装目录,然后进入到 “bin” 文件夹,单击 “visualvm.exe” 启动 VisualVM。
界面如下
在左侧的“Local” 下双击要监控的进程。即可进入监控界面
3. 远程连接
主要功能
- 生成/读取堆内存快照
- 查看JVM参数和系统属性
- 查看运行中的虚拟机进程
- 生成/读取线程快照
- 程序资源的实时监控
- 其他功能
- JMX代理连接
- 远程环境监控
- CPU分析和内存分析
生成堆内存/线程快照
在左侧的 “Local” 中通过进程生成堆内存/线程快照
在左侧的 “Local” 中右击要生成快照的进程
- 选择 “Heap Dump” 生成堆内存快照
- 选择 “Thread Dump” 生成线程快照
通过监视(Monitor)生成堆内存快照
堆内存快照如下:
这些快照存储在内存中,当线程停止的时候快照就会丢失,如果还想利用,可以将快照进行另存为操作,如下图:
通过线程(Threads)生成线程快照
线程快照如下:
这些快照存储在内存中,当线程停止的时候快照就会丢失,如果还想利用,可以将快照进行另存为操作,如下图:
载入堆内存/线程快照
通过 “File” →→ “Load” 打开选择快照对话框。
选择堆内存快照或线程快照即可装入。
JProfiler
基本概述
在运行 Java 的时候有时候想测试运行时占用内存情况,这时候就需要使用测试工具查看了。在 eclipse 里面有 Eclipse Memory Analyzer tool(MAT)插件可以测试,而在 IDEA 中也有这么一个插件,就是 JProfiler。JProfiler 是由 ej-technologies 公司开发的一款 Java 应用性能诊断工具。功能强大,但是收费。
特点:
- 使用方便、界面操作友好(简单且强大)
- 对被分析的应用影响小(提供模板)
- CPU,Thread,Memory 分析功能尤其强大
- 支持对 jdbc,noSql,jsp,servlet,socket 等进行分析
- 支持多种模式(离线,在线)的分析
- 支持监控本地、远程的 JVM
- 跨平台,拥有多种操作系统的安装版本
主要功能:
- 方法调用:对方法调用的分析可以帮助您了解应用程序正在做什么,并找到提高其性能的方法
- 内存分配:通过分析堆上对象、引用链和垃圾收集能帮您修复内存泄露问题,优化内存使用
- 线程和锁:JProfiler 提供多种针对线程和锁的分析视图助您发现多线程问题
- 高级子系统:许多性能问题都发生在更高的语义级别上。例如,对于 JDBC 调用,您可能希望找出执行最慢的 SQL 语句。JProfiler 支持对这些子系统进行集成分析
官网地址:https://www.ej-technologies.com/products/jprofiler/overview.html
安装与配置
下载与安装
下载地址:https://www.ej-technologies.com/download/jprofiler/files
一个神秘的下载地址:https://downloadlynet.ir/2020/12/1885/03/jprofiler/00/
JProfiler 中配置 IDEA
具体使用
数据采集方式
Profier 数据采集方式分为两种:Sampling(样本采集)和 Instrumentation(重构模式)
- Instrumentation:这是 JProfiler 全功能模式。在 class 加载之前,JProfier 把相关功能代码写入到需要分析的 class 的 bytecode 中,对正在运行的 jvm 有一定影响。
- 优点:功能强大。在此设置中,调用堆栈信息是准确的。
- 缺点:若要分析的 class 较多,则对应用的性能影响较大,CPU 开销可能很高(取决于 Filter 的控制)。因此使用此模式一般配合 Filter 使用,只对特定的类或包进行分析
- Sampling:类似于样本统计,每隔一定时间(5ms)将每个线程栈中方法栈中的信息统计出来。
- 优点:对 CPU 的开销非常低,对应用影响小(即使你不配置任何 Filter)
- 缺点:一些数据/特性不能提供(例如:方法的调用次数、执行时间)
注:JProfiler 本身没有指出数据的采集类型,这里的采集类型是针对方法调用的采集类型。因为 JProfiler 的绝大多数核心功能都依赖方法调用采集的数据,所以可以直接认为是 JProfiler 的数据采集类型。
遥感监测 Telemetries
实时内存视图 (Live Memory)
Live memory 内存剖析:class/class instance 的相关信息。例如对象的个数,大小,对象创建的方法执行栈,对象创建的热点。
- 所有对象 All Objects
显示所有加载的类的列表和在堆上分配的实例数。只有 Java 1.5(JVMTI)才会显示此视图。 - 记录对象 Record Objects
查看特定时间段对象的分配,并记录分配的调用堆栈。 - 分配访问树 Allocation Call Tree
显示一棵请求树或者方法、类、包或对已选择类有带注释的分配信息的 J2EE 组件。 - 分配热点 Allocation Hot Spots
显示一个列表,包括方法、类、包或分配已选类的 J2EE 组件。你可以标注当前值并且显示差异值。对于每个热点都可以显示它的跟踪记录树。 - 类追踪器 Class Tracker
类跟踪视图可以包含任意数量的图表,显示选定的类和包的实例与时间。
分析:内存中的对象的情况
- 频繁创建的 Java 对象:死循环、循环次数过多
- 存在大的对象:读取文件是,
byte[]
应该边读边写。 如果长时间不写出的话,导致byte[]
过大 - 存在内存泄漏
[!NOTE]
- All Objects 后面的 Size 大小是浅堆大小
- Record Objects 在判断内存泄露的时候使用,可以通过观察 Telemetries 中的 Memory,如果里面出现垃圾回收之后的内存占用逐步提高,这就有可能出现内存泄露问题,所以可以使用 Record Objects 查看,但是该分析默认不开启,毕竟占用 CPU 性能太多
堆遍历器 (Heap Walker)
CPU 视图 (CPU Views)
JProfiler 提供不同的方法来记录访问树以优化性能和细节。线程或者线程组以及线程状况可以被所有的视图选择。所有的视图都可以聚集到方法、类、包或 J2EE 组件等不同层上。
- 访问树 Call Tree:显示一个积累的自顶向下的树,树中包含所有在 JVM 中已记录的访问队列。JDBC,JMS 和 JNDI 服务请求都被注释在请求树中。请求树可以根据 Servlet 和 JSP 对 URL 的不同需要进行拆分。
- 热点 Hot Spots:显示消耗时间最多的方法的列表。对每个热点都能够显示回溯树。该热点可以按照方法请求,JDBC,JMS 和 JNDI 服务请求以及按照 URL 请求来进行计算。
- 访问图 Call Graph:显示一个从已选方法、类、包或 J2EE 组件开始的访问队列的图。
- 方法统计 Method Statistics:显示一段时间内记录的方法的调用时间细节。
线程视图 (Threads)
JProfiler通过对线程历史的监控判断其运行状态,并监控是否有线程阻塞产生,还能将一个线程所管理的方法以树状形式呈现。对线程剖析。
- 线程历史 Thread History:显示一个与线程活动和线程状态在一起的活动时间表。
- 线程监控 Thread Monitor:显示一个列表,包括所有的活动线程以及它们目前的活动状况。
- 线程转储 Thread Dumps:显示所有线程的堆栈跟踪。
线程分析主要关心三个方面:
- web 容器的线程最大数。比如:Tomcat 的线程容量应该略大于最大并发数。
- 线程阻塞
- 线程死锁
监控和锁 (Monitors &Locks)
所有线程持有锁的情况以及锁的信息。观察 JVM 的内部线程并查看状态:
- 死锁探测图表 Current Locking Graph:显示 JVM 中的当前死锁图表。
- 目前使用的监测器 Current Monitors:显示目前使用的监测器并且包括它们的关联线程。
- 锁定历史图表 Locking History Graph:显示记录在 JVM 中的锁定历史。
- 历史检测记录 Monitor History:显示重大的等待事件和阻塞事件的历史记录。
- 监控器使用统计 Monitor Usage Statistics:显示分组监测,线程和监测类的统计监测数据
案例分析
案例1
1 | import java.util.ArrayList; |
java
案例2:
1 | import java.util.ArrayList; |
Java Mission Control
历史
在 Oracle 收购 Sun 之前,Oracle 的 JRockit 虚拟机提供了一款叫做 JRockit Mission Control 的虚拟机诊断工具。
在 Oracle 收购 sun 之后,Oracle 公司同时拥有了 Hotspot 和 JRockit 两款虚拟机。根据 Oracle 对于 Java 的战略,在今后的发展中,会将 JRokit 的优秀特性移植到 Hotspot 上。其中一个重要的改进就是在 Sun 的 JDK 中加入了 JRockit 的支持。
在 Oracle JDK 7u40 之后,Mission Control 这款工具己经绑定在 Oracle JDK 中发布。
自 Java11 开始,本节介绍的 JFR 己经开源。但在之前的 Java 版本,JFR 属于 Commercial Feature 通过 Java 虚拟机参数 -XX:+UnlockCommercialFeatures
开启。
- 官方地址:https://openjdk.org/projects/jmc
- Github项目地址:https://github.com/openjdk/jmc
概述
Java Mission Control(简称 JMC) , Java 官方提供的性能强劲的工具,是一个用于对 Java 应用程序进行管理、监视、概要分析和故障排除的工具套件。
它包含一个 GUI 客户端以及众多用来收集 Java 虚拟机性能数据的插件如 JMX Console(能够访问用来存放虚拟机齐个于系统运行数据的 MXBeans)以及虚拟机内置的高效 profiling 工具 Java Flight Recorder(JFR)。
JMC 的另一个优点就是:采用取样,而不是传统的代码植入技术,对应用性能的影响非常非常小,完全可以开着 JMC 来做压测(唯一影响可能是 full gc 多了)。
启动
Mission Control 位于 %JAVA_HOME%/bin/jmc.exe
功能:实时监控JVM运行时的状态
如果是远程服务器,使用前要开 JMX。
-Dcom.sun.management.jmxremote.port=${YOUR PORT}
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=${YOUR HOST/IP}
文件 ->连接 ->创建新连接, 填入上面 JMX 参数的 host 和 port
Java Flight Recorder
Java Flight Recorder 是 JMC 的其中一个组件。
Java Flight Recorder 能够以极低的性能开销收集 Java 虚拟机的性能数据。
JFR 的性能开销很小,在默认配置下平均低于 1%。与其他工具相比,JFR 能够直接访问虚拟机内的数据,并且不会影响虚拟机的优化。因此,它非常适用于生产环境下满负荷运行的 Java 程序。
时间类型
Java Flight Recorder 和 JDK Mission Control 共同创建了一个完整的工具链。JDKMission Control 可对 Java Flight Recorder 连续收集低水平和详细的运行时信息进行高效详细的分析。
当启用时 JFR将记录运行过程中发生的一系列事件。其中包括Java层面的事件如线程事件、锁事件,以及Java虚拟机内部的事件,如新建对象,垃圾回收和即时编译事件。
按照发生时机以及持续时间来划分,JFR的事件共有四种类型,它们分别为以下四种:
- 瞬时事件(Instant Event) ,用户关心的是它们发生与否,例如异常、线程启动事件。
- 持续事件(Duration Event) ,用户关心的是它们的持续时间,例如垃圾回收事件。
- 计时事件(Timed Event) ,是时长超出指定阈值的持续事件。
- 取样事件(Sample Event),是周期性取样的事件。
取样事件的其中一个常见例子便是方法抽样(Method Sampling),即每隔一段时问统计各个线程的栈轨迹。如果在这些抽样取得的栈轨迹中存在一个反复出现的方法,那么我们可以推测该方法是热点方法
启动方式
方式1:使用 -XX:StartFlightRecording=参数
第一种是在运行目标 Java 程序时添加 -XX:startFlightRecording=参数
。
比如: 下面命令中,JFR 将会在 Java 虚拟机启动 5s 后 (对应 delay=5s
) 收集数据,持续 20s(对应 duration=28s
)。当收集完毕后,JFR 会将收集得到的数据保存至指定的文件中(对应 filename=myrecording.jfr
)
1 | java -XX:StartFlightRecording=delay=5s,duration=20s,filename=myrecording.jfr,settings=profile MyApp |
shell
由于 JFR 将持续收集数据,如果不加以限制,那么 JFR 可能会填满硬盘的所有空间。因此,我们有必要对这种模式下所收集的数据进行限制。
比如:
1 | java -XX:StartFlightRecording=maxage=10m,maxsize=100m,name=SomeLabel MyApp |
shell
方式2:使用 jcmd 的JFR.*子命令
通过jcmd来让 JFR 开始收集数据、停止收集数据,或者保存所收集的数据,对应的子命令分别为JFR.start, JFR.stop,以及JFR.dump。
1 | jcmd <PID> JFR.start settings=profile maxage=10m maxsize=150m name=SomeLabel |
shell
上述命令运行过后,目标进程中的 JFR 已经开始收集数据。此时,我们可以通过下述命令来导出已经收集到的数据:
1 | jcmd <PID> JFR.dump name=SomeLabel filename=myrecording.jfr |
shell
最后,我们可以通过下述命令关闭目标进程中的 JFR:
1 | jcmd <PID> JFR.stop name=SomeLabel |
shell
1、启动飞行记录仪
2、正式启动
Java Flight Recorder 取样分析
要采用取样,必须先添加参数:
-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder
JDK9及更高版本
-XX:+UnlockCommercialFeatures
-XX:+StartFlightRecording
如:-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=200s
否则:
提示
第一张图片中的错误是最新版本中的错误,下面的图可能是一个早期版本中的错误
取样时间默认 1 分钟,可自行按需调整,事件设置选为profiling,然后可以设置取样 profile哪些信息,比如:
- 加上对象数量的统计: Java Virtual Machine →→ Gc →→ Detailed →→ ObjectCount/Object Count after GC
- 方法调用采样的间隔从 10ms 改为 1ms(但不能低于 1ms,否则会影响性能了): JavaVirtual Machine →→ Profiling →→ Method Profiling Sample/Method SamplingInformation
- Socket 与 File 采样,10ms 太久,但即使改为 1ms 也未必能抓住什么,可以干脆取消掉:Java Application →→ File Read/FileWrite/Socket Read/Socket Write
然后就开始 Profile,到时间后 Profile 结束,会自动把记录下载回来,在 JMC 中展示。
从展示信息中,我们大致可以读到内存和 CPU 信息、代码、线程和 IO 等比较重要的信息展示。
1 | import java.util.ArrayList; |