虚拟机性能监控与故障处理 — 两个可视化工具 — JVM系列(十二)

一、前言

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进行性能监视、定位连接泄漏、解决多线程竞争问题等的例子。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章