前言
VisualVM在JDK 6 Update 7中首次发布,直到JRockit Mission Control与OracleJDK的融合工作完成之前,它都曾是Oracle主力推动的多合一故障处理工具,现在它已经从OracleJDK中分离出来,成为一个独立发展的开源项目。 VisualVM已不是JDK中的正式成员,但仍是可以免费下载、使用的。
VisualVM( All-in-One Java Troubleshooting Tool)是功能最强大的运行监视和故障处理程序之一,曾经在很长一段时间内是Oracle官方主力发展的虚拟机故障处理工具。 Oracle曾在VisualVM的软件说明中写上了“All-in-One”的字样,表示着它除了常规的运行监视、故障处理外,还将提供其他方面的能力,例如性能分析( Profiling)。 VisualVM的性能分析功能相比JProfiler、 YourKit等专业且收费的Profiling工具并不逊色。而且相比这些第三方工具,VisualVM还有一个很大的优点:不需要被监视的程序基于特殊Agent去运行,所以它的通用性很强,对应用程序实际性能的影响也较小,使得它可以直接应用在生产环境中。这个优点是JProfiler、 YourKit等工具无法与之相比的。
一、VisualVM兼容范围与插件安装
VisualVM基于NetBeans平台开发工具,所以一开始它就具备了通过插件扩展功能的能力,有了插件扩展支持, VisualVM可以做到:
-
显示虚拟机进程以及进程的配置、环境信息( jps、 jinfo)。 -
监视应用程序的处理器、垃圾收集、堆、方法区以及线程的信息( jstat、 jstack)。 -
dump以及分析堆转储快照( jmap、 jhat)。 -
方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法。 -
离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照发送开发者处进行Bug反馈。 -
其他插件带来的无限可能性。
VisualVM在JDK 6 Update 7中首次发布,但并不意味着它只能监控运行于JDK 6上的程序,它具备很优秀的向下兼容性,甚至能向下兼容至2003年发布的JDK 1.4.2版本[1],这对无数处于已经完成实施、正在维护的遗留项目很有意义。当然,也并非所有功能都能完美地向下兼容,主要功能的兼容性见表所示。
首次启动VisualVM后,先不必着急找应用程序进行监测,初始状态下的VisualVM并没有加载任何插件,虽然基本的监视、线程面板的功能主程序都以默认插件的形式提供,但是如果不在VisualVM上装任何扩展插件,就相当于放弃它最精华的功能,和没有安装任何应用软件的操作系统差不多。
VisualVM的插件可以手工进行安装,在网站上下载nbm包后,点击“工具->插件->已下载”菜单,然后在弹出对话框中指定nbm包路径便可完成安装。独立安装的插件存储在VisualVM的根目录,例如JDK 9之前自带的VisulalVM,插件安装后是放在JDK_HOME/lib/visualvm中的。手工安装插件并不常用, VisualVM的自动安装功能已可找到大多数所需的插件,在有网络连接的环境下,点击“工具->插件菜单”,弹出如下图所示的插件页签,在页签的“可用插件”及“已安装”中列举了当前版本VisualVM可以使用的全部插件,选中插件后在右边窗口会显示这个插件的基本信息,如开发者、版本、功能描述等。
读者可根据自己的工作需要和兴趣选择合适的插件,然后点击“安装”按钮,弹出如下图所示的下载进度窗口,跟着提示操作即可完成安装。
选择一个需要监视的程序就可以进入程序的主界面了,如图所示。由于VisualVM的版本以及选择安装插件数量的不同,读者看到的页签可能和笔者的截图有所差别。
VisualVM中“概述”“监视”“线程”“MBeans”的功能与前面介绍的JConsole差别不大,读者可根据上一节内容类比使用,这里笔者挑选几个有特色的功能和插件进行简要介绍。
二、生成、浏览堆转储快照
在VisualVM中生成堆转储快照文件有两种方式,可以执行下列任一操作:
- 在“应用程序”窗口中右键单击应用程序节点,然后选择“堆Dump”。
- 在“应用程序”窗口中双击应用程序节点以打开应用程序标签,然后在“监视”标签中单击“堆Dump”。
生成堆转储快照文件之后,应用程序页签会在该堆的应用程序下增加一个以[heap-dump]开头的子节点,并且在主页签中打开该转储快照,如下图所示。如果需要把堆转储快照保存或发送出去,就应在heapdump节点上右键选择“另存为”菜单,否则当VisualVM关闭时,生成的堆转储快照文件会被当作临时文件自动清理掉。要打开一个由已经存在的堆转储快照文件,通过文件菜单中的“装入”功能,选择硬盘上的文件即可。
堆页签中的“摘要”面板可以看到应用程序dump时的运行时参数、 System.getPro-perties()的内容、线程堆栈等信息; “类”面板则是以类为统计口径统计类的实例数量、容量信息; “实例”面板不能直接使用,因为VisualVM在此时还无法确定用户想查看哪个类的实例,所以需要通过“类”面板进入,在“类”中选择一个需要查看的类,然后双击即可在“实例”里面看到此类的其中500个实例的具体属性信息; “OQL控制台”面板则是运行OQL查询语句的,同jhat中介绍的OQL功能一样。
三、分析程序性能
在Profiler页签中, VisualVM提供了程序运行期间方法级的处理器执行时间分析以及内存分析。做Profiling分析肯定会对程序运行性能有比较大的影响,所以一般不在生产环境使用这项功能,或者改用JMC来完成, JMC的Profiling能力更强,对应用的影响非常轻微。
要开始性能分析,先选择“CPU”和“内存”按钮中的一个,然后切换到应用程序中对程序进行操作, VisualVM会记录这段时间中应用程序执行过的所有方法。如果是进行处理器执行时间分析,将会统计每个方法的执行次数、执行耗时;如果是内存分析,则会统计每个方法关联的对象数以及这些对象所占的空间。等要分析的操作执行结束后,点击“停止”按钮结束监控过程,如下图所示。
四、BTrace动态日志跟踪
BTrace是一个很神奇的VisualVM插件,它本身也是一个可运行的独立程序。 BTrace的作用是在不中断目标程序运行的前提下,通过HotSpot虚拟机的Instrument功能动态加入原本并不存在的调试代码。这项功能对实际生产中的程序很有意义:如当程序出现问题时,排查错误的一些必要信息时(例如方法参数、返回值等),在开发时并没有打印到日志之中以至于不得不停掉服务时,都可以通过调试增量来加入日志代码以解决问题。
在VisualVM中安装了BTrace插件后,在应用程序面板中右击要调试的程序,会出现“Trace Application…”菜单,点击将进入BTrace面板。这个面板看起来就像一个简单的Java程序开发环境,里面甚至已经有了一小段Java代码,如下图所示。 下面准备了一段简单的Java代码来演示BTrace的功能:产生两个1000以内的随机整数,输出这两个数字相加的结果,如代码清单所示。
public class BTraceTest {
public int add(int a, int b) {
return a + b;
}
public static void main(String[] args) throws IOException {
BTraceTest test = new BTraceTest();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
for (int i = 0; i < 10; i++) {
reader.readLine();
int a = (int) Math.round(Math.random() * 1000);
int b = (int) Math.round(Math.random() * 1000);
System.out.println(test.add(a, b));
}
}
}
假设这段程序已经上线运行,而我们现在又有了新的需求,想要知道程序中生成的两个随机数是什么,但程序并没有在执行过程中输出这一点。此时,在VisualVM中打开该程序的监视,在BTrace页签填充TracingScript的内容,输入调试代码,如代码清单所示,即可在不中断程序运行的情况下做到这一点。
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
@OnMethod(
clazz="org.fenixsoft.monitoring.BTraceTest",
method="add",
location=@Location(Kind.RETURN)
)
public static void func(@Self org.fenixsoft.monitoring.BTraceTest instance,int a, int b,@Return int result) {
println("调用堆栈:");
jstack();
println(strcat("方法参数A:",str(a)));
println(strcat("方法参数B:",str(b)));
println(strcat("方法结果:",str(result)));
}}
点击Start按钮后稍等片刻,编译完成后, Output面板中会出现“BTrace code successfuly deployed”的字样。当程序运行时将会在Output面板输出如图所示的调试信息。
BTrace的用途很广泛,打印调用堆栈、参数、返回值只是它最基础的使用形式,在它的网站上有使用BTrace进行性能监视、定位连接泄漏、内存泄漏、解决多线程竞争问题等的使用案例。
BTrace能够实现动态修改程序行为,是因为它是基于Java虚拟机的Instrument开发的。 Instrument是Java虚拟机工具接口(Java Virtual Machine Tool Interface, JVMTI)的重要组件,提供了一套代理(Agent)机制,使得第三方工具程序可以以代理的方式访问和修改Java虚拟机内部的数据。阿里巴巴开源的诊断工具Arthas也通过Instrument实现了与BTrace类似的功能。
结尾
- 感谢大家的耐心阅读,如有建议请私信或评论留言。
- 如有收获,劳烦支持,关注、点赞、评论、收藏均可,博主会经常更新,与大家共同进步
|