性能监控之可视化故障处理工具 Visualvm

1.Visualvm兼容范围与插件安装

  Visualvm基于NetBeans平台开发工具,具备通过插件扩展功能的能力。有了插件扩展功能,Visualvm可以做到:

  • 显示虚拟机进程以及进程的的配置,环境信息(jps,jinfo)
  • 监视应用存储的处理器,垃圾收集,堆,方法区以及线程的信息(jstat,jstack)
  • dump及分析堆转储快照(jmap,jhat)
  • 方法级的程序运行性能分析,找出被调用最多,运行时间最长的方法
  • 离线程序快照:收集程序的运行时配置,线程dump,内存dump等信息建立一个快照,可以将快照发送给开发者进行Bug反馈

2.生成,浏览堆转储快照

  生成堆转储快照有两种方式:

  • 在“应用程序”窗口中右键应用程序节点,选择“堆Dump"
  • 在“应用程序”窗口中双击应用程序节点,打开应用程序标签,然后在”监视“标签中单击”堆Dump“

  [heapdump]文件是临时文件,需要手动保存。手动保存的dump文件可以通过 文件 -> 装入 功能打开

  

 

3.程序性能分析

  在Profiler页签中,Visualvm提供了程序运行期间方法级的处理器执行时间分析和内存分析。做Profiling分析对程序运行性能有较大影响,所以一般不会在生产环境使用该功能。

4.BTrace动态日志追踪

  Btrace的作用是在不中断目标程序运行的前提下,通过HotSpot的Instrument功能动态添加原本不存在的调试代码。

package com.ryj.hotspot;

import java.util.ArrayList;
import java.util.List;

import com.ryj.java8.lambda.apple.Apple;

public class JavaHeapTest {

    static List<Apple> appleList = new ArrayList<>();

    public static void main(String[] args) {
        verificationOOM();
    }

    private static void verificationOOM() {
        Integer i = 0;
        while (true) {
            addApple(++i);
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    private static Apple addApple(Integer a) {
        System.out.println(a);
        Apple apple = new Apple("red", 12.5f); 
        appleList.add(apple);
        return  apple;
    }
}
View Code
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import com.alibaba.fastjson.JSON;
import static com.sun.btrace.BTraceUtils.*;

@BTrace(unsafe = true)
public class TracingScript {
	/* put your code here */
    @TLS private static long startTime = 0;

    @OnMethod(clazz="com.ryj.hotspot.JavaHeapTest",method="addApple")
    public static void startExecute(){
       startTime = timeNanos();
       //println(strcat("开始时间: ",str(startTime)));
    }
   
   @OnMethod(clazz="com.ryj.hotspot.JavaHeapTest",method="addApple",location=@Location(Kind.RETURN))
    public static void endExecute(@Self com.ryj.hotspot.JavaHeapTest instance, Integer a, @Return com.ryj.java8.lambda.apple.Apple apple){
       long endTime = timeNanos();
       //println(strcat("结束时间: ",str(endTime)));
       println(strcat("方法参数A: ",str(a)));
       println(strcat("execute time(nanos): ", str(endTime-endTime)));
       //println(strcat("result: ", str(apple.toString())));  
       println(strcat("result: ", JSON.toJSONString(apple)));
   }
}
View Code

  Btrace之所以安全可靠的,是因为它对正在运行的程序是只读的。也就是说,他可以插入跟踪语句来检测和分析运行中的程序,不允许对其进行修改。因此他存在一些限制:

  • 不能创建对象
  • 不能创建数组
  • 不能抛出和捕获异常
  • 不能调用任何对象方法和静态方法
  • 不能给目标程序中的类静态属性和对象的属性进行赋值
  • 不能有外部、内部和嵌套类
  • 不能有同步块和同步方法
  • 不能有循环(for, while, do..while)
  • 不能继承任何的类
  • 不能实现接口
  • 不能包含assert断言语句

  这些限制其实是可以使用unsafe模式绕过,通过声明 *@BTrace(unsafe = true) annotation。实际使用非安全模式跟踪时,发现一个问题,一个进程如果被安全模式btrace探测过一次, 后面再使用非安全模式进行探测时非安全模式不生效。

  • @BTrace 声明了这个类是BTrace脚本。unsafe参数表示是否不安全的模式执行.
  • @OnMethod 声明了关注点,必须声明在公有的静态方法上public static void。静态方法为 在关注点上执行的跟踪动作
  • @TLS声明的变量是 ThreadLocal的, 每个线程都会有一份这个自己的startTime 变量
  • location: 用@Location来表明在什么时候时候去执行脚本
  • @Self 声明探测的当前对象this
  • @Return 方法返回对象

  基本实现逻辑:虚拟机其实提供了一个hook,那就是Instrumentation,可以将独立于应用程序的代理程序agent程序随着着应用程序一起启动或者attach挂载到正在运行中的应用程序。而在代理程序中可以对class进行修改或者重新定义。

原文地址:https://www.cnblogs.com/ryjJava/p/12639608.html