一、前言
JDK中除了提供大量的命令行工具外,还有两个功能强大的可视化工具Jconsole和VisualVM。
二、Jconsole
Jconsole是一种基于JMX的可视化监视、管理工具,它管理部分的功能是针对JMX MBean进行管理,我们主要关注的是Jconsole的监控部分的功能。
Jconsole既可以监控本地进程,也可以连接远程的服务器。
我们打开JDK中的Jconsole,然后选择想要监控的进程就可以了。
Jconsole的主界面包括以下6个标签:
- 概述:包括了堆内存使用情况、线程、类、CPU使用情况4种信息的曲线图。
- 内存:相当于可视化的jstat命令,用来监视受收集器管理的虚拟机内存(Java堆和永久代)的变化趋势。
- 线程:相当于可视化的jstack命令,遇到线程停顿时可以使用这个页签进行监控分析,可能是等待外部资源,循环或者锁等待的原因。可以检测死锁的情况。
- 类
- VM摘要
- MBean
三、VisualVM
目前为止,随着JDK发布的功能最强大的运行监视和故障处理程序。
同时VisualVM还有性能分析的功能,它的性能分析功能比JProfile等专业收费的工具也不会逊色。
因为VisualVM不需要被监视的程序基于特殊的Agent运行,因此它对应用程序的实际性能影响很小,可以直接用在生产环境中。
VisualVM具有插件扩展的功能,可以安装很多的插件。
VisualVM可以做到:
- 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)。
- 监视应用程序的CPU、GC、堆、方法区以及线程的信息(jstat、jstack)。
- dump以及分析堆转储快照(jmap、jhat)。
- 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法。
- 离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照发送开发者处进行Bug反馈。
- 其他plugins的无限的可能性。
1、如何dump堆和线程
我们可以进行堆的dump或者线程的dump,然后会在对应的进程下面直接生成这两个文件,但是如果需保存的话,需要将其另存为,同时后期想要继续分析dump文件的话,可以通过装入功能引入dump文件。
我们可以在堆的dump文件的摘要面板上看到dump时的运行时参数、System.getProperties( )内容,线程堆栈等信息。
2、类面板
类面板可以看到以类为统计口径的统计类的实例数量、容量信息。
3、实例面板
实例面板不能直接使用,因为不能确定用户想看哪个类的实例,所以需要通过类面板进入。
4、Profiler的使用
在Profiler页签中,VisualVM提供了程序运行期间方法级的CPU执行时间分析以及内存分析,做Profiling分析肯定对程序运行性能有比较大的影响,所以一般不在生产环境中使用这项功能。
首先选择CPU和内存按钮中的一个,然后切换到应用程序对程序进行操作,VisualVM会记录到这段时间中应用程序执行过的方法。
如果是CPU分析,将会统计每个方法的执行次数、执行耗时。
如果是内存分析,则会统计每个方法关联的对象数以及这些对象所占的空间。
分析结束后,点击停止按钮结束监控过程。
5、BTrace的使用
BTrace是一个很有趣的VisualVM插件,本身也是可以独立运行的程序。
它的作用是在不停止目标程序运行的前提下,通过虚拟机的HotSwap技术动态加入原本不存在的调试代码。
这项功能对实际生产中的程序很有意义,可以在不停服务的情况下,方便添加日志,进而排查问题。
我们安装完BTrace插件后,在应用程序面板中右键点击要调试的程序,会出现Trace Application菜单,点击进入BTrace面板。
这个面板里面看起来就像一个简单的Java程序开发环境,里面还有一段Java代码,如下图所示:
我们通过一个程序的例子,源代码如下:
package com.example.demo.jvm;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
// 产生两个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的内容,程序如下所示:
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
@BTrace
public class TracingScript {
/* put your code here */
@OnMethod(
clazz = "com.example.demo.jvm.BTraceTest",
method = "add",
location = @Location(Kind.RETURN)
)
public static void func(@Self com.example.demo.jvm.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进行性能监视、定位连接泄漏、解决多线程竞争问题等的例子。