【十四】不要问我JVM !—— 性能调优工具
使用上述命令行工具或组合能帮您获取目标 Java 应用性能相关的基础信息,但它们存在下列局限:
- 无法获取方法级别的分析数据,如方法间的调用关系、各方法的调用次数和调用时间等(这对定位应用性能瓶颈至关重要)。
- 要求用户登录到目标 Java 应用所在的宿主机上,使用起来不是很方便。
- 分析数据通过终端输出,结果展示不够直观。
为此,JDK提供了一些内存泄漏的分析工具,如jconsole、jvisualvm等,用于辅助开发人员定位问题,但是这些工具很多时候并不足以满足快速定位的需求。所以这里我们介绍的工具相对多一些、丰富一些。
一、工具种类
JDK自带
- jconsole:JDK自带的可视化监控工具。查看Java应用程序的运行概况、监控堆信息、永久区(或元空间)使用情况、类加载情况等。位置:jdk\bin\jconsole.exe
- Visual VM:Visual VM是一个工具,它提供了一个可视界面,用于查看Java虚拟机上运行的基于Java技术的应用程序的详细信息。位置:jdk\bin\jvisualvm.exe
- JMC:Java Mission Control,内置Java Flight Recorder。能够以极低的性能开销收集Java虚拟机的性能数据。
第三方
- MAT:MAT(Memory Analyzer Tool)是基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。Eclipse的插件形式。
- JProfiler:商业软件,需要付费。功能强大。与VisualVM类似。
- Arthas:Alibaba开源的Java诊断工具。深受开发者喜爱。
- Btrace:Java运行时追踪工具。可以在不停机的情况下,跟踪指定的方法调用、构造函数调用和系统内存等信息。
二、JConsole
从Java5开始,在JDK中自带的java监控和管理控制台。
用于对JVM中内存
、线程
和类
等的监控,是一个基于JMX(Java Management Extensions)
的GUI性监控工具。
官方教程:https://docs.oracle.com/javase/7/docs/technotes/guides/management/jconsole.html
/**
* -Xms600m -Xmx600m -XX:SurvivorRatio=8
*/
public class HeapInstanceTest {
byte[] buffer = new byte[new Random().nextInt(1024 * 100)];
public static void main(String[] args) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ArrayList<HeapInstanceTest> list = new ArrayList<>();
while (true) {
list.add(new HeapInstanceTest());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
检查堆内存的使用量,能够看不同区的分配情况
线程信息
类加载
VM信息
死锁检测
三、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
3.1 插件的安装
插件地址:https://visualvm.github.io/pluginscenters.html
Visual VM的一大特点是支持插件扩展,并且插件安装非常方便。我们既可以通过离线下载插件文件*.nbm,然后在Plugin对话框的已下载页面下,添加已下载的插件。也可以在可用插件页面下,在线安装插件。(这里建议安装上:VisualGC)
IDEA安装VisualVM Launcher插件
Preferences→Plugins→搜索VisualVM Launcher,安装重启即可。
本地连接
监控本地Java进程的CPU、类、线程等
远程连接
- 确定远程服务器的ip地址
- 添加JMX(通过JMX技术具体监控远程服务器哪个Java进程)
- 修改bin/catalina.sh文件,连接远程的tomcat
- 在…/conf中添加jmxremote.access和jmxremote.password文件
- 将服务器地址改成公网ip地址
- 设置阿里云安全策略和防火墙策略
- 启动tomcat,查看tomcat启动日志和端口监听
- JMX中输入端口号、用户名、密码登录
3.2 主要功能
public class OOMTest {
public static void main(String[] args) {
ArrayList<Picture> list = new ArrayList<>();
while (true) {
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(new Picture(new Random().nextInt(10 * 50)));
}
}
}
class Picture {
private byte[] pixels;
public Picture(int length) {
this.pixels = new byte[length];
}
}
3.2.1 生成/读取堆内存快照
生成Dump文件
方式1:
方式二:
保存Dump文件
读取Dump文件
OQL查询
死锁检测
查看JVM参数和系统属性
JVM参数
系统属性
查看运行中的虚拟机进程
程序资源的实时监控
其他功能
JMX代理连接
远程环境监控
CPU分析和内存分析
CPU采样,可以看到对CPU占用比较长的方法
内存采样,可以看到哪些结构的实例数和占用的字节数
四、Eclipse MAT
MAT(Memory Analyzer Tool)工具是一款功能强大的Java堆内存分析器。可以用于查找内存泄漏以及查看内存消耗情况。
MAT是基于Eclipse开发的,不仅可以单独使用,还可以作为插件的形式嵌入在Eclipse中使用。是一款免费的性能分析工具,使用起来非常方便。大家可以在 https://www.eclipse.org/mat/downloads.php 下载并使用MAT。
只要确保机器上装有JDK并配置好相关的环境变量,MAT可正常启动。
4.1 获取堆Dump文件
dump文件内容
MAT可以分析heap dump文件。在进行内存分析时,只要获得了反映当前设备内存映像的hprof文件,通过MAT打开就可以直观地看到当前的内存信息。
一般说来,这些内存信息包含:
- 所有的对象信息,包括对象实例、成员变量、存储于栈中的基本类型值和存储于堆中的其他对象的引用值。
- 所有的类信息,包括classloader、类名称、父类、静态变量等
- GCRoot到所有的这些对象的引用路径
- 线程信息,包括线程的调用栈及此线程的线程局部变量(TLS)
两点说明
说明1 缺点:
不是万能工具,它并不能处理所有类型的存储文件。但是比较主流的厂家和格式,例如Sun、HP、SAP所用的HPROF二进制存储文文件,以及IBM的PD堆存储文件等都能良好的解析。
说明2:
最吸引是能内存泄露报表,方便定位问题和分析问题。虽然MAT有如此强大的功能,但是内存分析没有简单到一键完成的的程度,很多内存问题还是需要从MAT展现给我们信息当中通过经验直觉来判断i才能能发现。
获取dump文件
方法一:通过前一章介绍的jmap工具生成,可以生成任意一个java进程的dump文件
方法二:通过配置JVM参数生成
- 选项
-XX:+HeapDumpOnOutofMemoryError
或-XX:+HeapDumpBeforeFullGC
- 选项
-XX:HeapDumpPath
就是当程序出现OOM时,将会在相应的目录下生成一份dump文件。如不指定则在当前目录下生成。
对比:考虑到生产环境中几乎不可能在线对其进行分析,大都是采用离线分析,因此使用jmap
+MAT
工具是最常见的组合。
方法三:使用VisualVM可以导出堆dump文件
方法四:使用MAT既可以打开一个已有的堆快照,也可以通过MAT直接从活动Java程序中导出堆快照。该功能将借助jps列出当前正在运行的Java进程,以供选择并获取快照。
分析堆Dump文件
生成文件和报告
选择Leak Suspects Report
在dump文件目录下回发现一个a_Leak_Suspects.zip
选项分析
- Leak Suspects Report:内存泄漏疑点报告
- Component Report:组件报告
- Re-open previously run reports:重新打开之前已经运行过的报告
概览
堆文件Overview
histogram
展示了各个类的实例数目以及这些实例的Shallow heap或者Retained heap的总和
在左边可以看到某一个类的信息
可以根据包名group by
可以排序
查看引用,可以看到被一个ArrayList引用
查看系统中的Java线程
查看局部变量的信息
获得对象相互引用的关系
with outgoing references 该局部变量引用了谁
with incoming references 谁引用了我