it_worker365

   ::  ::  ::  ::  :: 管理

利用hotswap技术,动态将跟踪字节码注入到运行类中,对运行代码侵入较小,对性能上的影响可以忽略不计

1、追踪方法的调用,参数返回值,执行时间,响应时间

2、定时打印调用次数,监控对某方法的调用

3、打印系统/JVM等信息,堆和非堆内存实时信息

4、接口性能变慢,分析每个方法的耗时情况;

5、当在Map中插入大量数据,分析其扩容情况;

6、分析哪个方法调用了System.gc(),调用栈如何;

7、执行某个方法抛出异常时,分析运行时参数;等等

BTrace Gradle方式安装:

1. 预先安装有Jdk, Git, Gradle

2. 下载代码: https://github.com/btraceio/btrace

3. 构建,如下,完成后在<btrace>/build/distributions/下有对应的构建包,解压将bin配置到path即可使用

cd <btrace> 
./gradlew build 
./gradlew buildDistributions

BTrace入门尝试,首先编写一个类,持久运行,模拟线上不断运行的系统

import java.util.Random;
/**
 * Created by itworker365 on 5/17/2017.
 */
public class Calculator {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        Random random = new Random();
        while (true) {
            System.out.println(calculator.add(random.nextInt(10), random.nextInt(10)));
        }
    }
    private int c = 1;
    public int add(int a, int b) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return a + b;
    }
}

编写BTrace文件BTraceTest.java内容如下,jps查到运行的系统进程号,运行命令btrace 进程号 BTraceTest.java

import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
/**
 * Created by itworker365 on 5/17/2017.
 */
@BTrace
public class BTraceTest {
    private static long count;
    @TLS
    private static long startTime=0;

    static{
        println("---------------------------JVM properties:---------------------------");
        printVmArguments();
        println("---------------------------System properties:------------------------");
        printProperties();
        println("---------------------------OS properties:----------------------------");
        printEnv();
    }
    //对Calculator的add方法的参数和返回值进行追踪
    @OnMethod(clazz = "Calculator", method = "add", location = @Location(Kind.RETURN))
    public static void trace1(int a, int b, @Return int sum) {
        println("trace1:a=" + a + ",b=" + b + ",sum=" + sum);
        jstack();
    }
    //对Calculator的add方法的持续时间进行追踪,计算耗时
    @OnMethod(clazz = "Calculator", method = "add", location = @Location(Kind.RETURN))
    public static void trace2(@Duration long duration) {
        println(strcat("duration(nanos): ", str(duration)));
        println(strcat("duration(s): ", str(duration / 1000000000)));
        print("[");
        print(strcat("Time taken: ",str(timeMillis()-startTime)));
        println("]");
    }
    //对Calculator的add方法中的任何类的sleep方法进行追踪
    @OnMethod(clazz = "Calculator", method = "add", location = @Location(value = Kind.CALL, clazz = "/.*/", method = "sleep"))
    public static void trace3(@ProbeClassName String pcm, @ProbeMethodName String pmn, @TargetInstance Object instance, @TargetMethodOrField String method) {
        println(strcat("ProbeClassName: ", pcm));
        println(strcat("ProbeMethodName: ", pmn));
        println(strcat("TargetInstance: ", str(instance)));
        println(strcat("TargetMethodOrField : ", str(method)));
        println(strcat("count: ", str(++count)));

    }
    //每隔6秒打印一次count
    @OnTimer(6000)
    public static void trace4() {
        println(strcat("trace4:count: ", str(count)));
    }
    //获取 Calculator类的c属性的值
    @OnMethod(clazz = "Calculator", method = "add", location = @Location(Kind.RETURN))
    public static void trace5(@Self Object calculator) {
        println(get(field("Calculator", "c"), calculator));
    }
    //每隔4秒打印一次印堆和非堆内存信息
    @OnTimer(4000)
    public static void traceMemory() {
        println("heap:");
        println(heapUsage());
        println("no-heap:");
        println(nonHeapUsage());
    }
    //每隔4秒检测是否有死锁产生,并打印产生死锁的相关类信息、对应的代码行、线程信息
    @OnTimer(4000)
    public static void trace6() {
        deadlocks();
    }
}

 结果节选:

ProbeClassName: Calculator
ProbeMethodName: add
TargetInstance: null
TargetMethodOrField : sleep
count: 36
trace4:count: 36
heap:
init = 16777216(16384K) used = 6802480(6643K) committed = 16252928(15872K) max = 253427712(247488K)
no-heap:
init = 2555904(2496K) used = 11498280(11228K) committed = 11796480(11520K) max = -1(-1K)
1
duration(nanos): 0
duration(s): 0
[Time taken: 1495003046282]
trace1:a=7,b=8,sum=15
Calculator.add(Calculator.java:20)
Calculator.main(Calculator.java:10)

注解说明-copy

1)类注解
@com.sun.btrace.annotations.BTrace指定该java类为一个btrace脚本文件。
2)属性注解
@TLS标注的属性可以在追踪脚本的方法中通讯
3)方法注解
@OnMethod:指定该方法在什么情况下被执行
clazz属性指定要跟踪的类的全限定类名,也可以用正则表达式,“
/类名的Pattern/”匹配,如/javax\\.swing\\..*/;
用”+类名”追踪所有子类,如+java.lang.Runnable;
用”@xxx”追踪用该注解注解过的类,如@javax.jws.WebService。
method属性指定要追踪的方法名称,也可以用正则表达式。
location属性用@Location来指定该方法在目标方法执行前(后、异常、某行、某个方法调用)被执行。 @OnTimer:定时执行该方法。 @OnExit:当脚本运行Sys.exit(code)时执行该方法。 @OnError:当脚本运行抛出异常时执行该方法。 @OnEvent:脚本运行时Ctrl
+C可以发送事件。 @OnLowMemory:指定一个内存阀值,低于阀值值执行该方法。 @OnProbe:指定一个xml文件来描述在什么时候执行该方法。 4)方法参数注解 @Self:指目标对象本身。 @Retrun:指目标程序方法返回值(需要配合Kind.RETURN)。 @ProbeClassName:指目标类名。 @ProbeMethodName:指目标方法名。 @targetInstance:指@Location指定的clazz和method的目标(需要配合Kind.CALL)。 @targetMethodOrField:指@Location指定的clazz和method的目标的方法或字段(需要配合Kind.CALL)。 @Duration:指目标方法执行时间,单位是纳秒(需要需要配合Kind.RETURN或Kind.ERROR一起使用)。 AnyType:获取对应请求的参数,泛指任意类型。 9.追踪时机参数 Kind.Entry:开始进入目标方法时,默认值。 Kind.Return:目标方法返回时。 Kind.Error:异常没被捕获被抛出目标方法之外时。 Kind.Throw:异常抛出时。 Kind.Catch:异常被捕获时。 Kind.Call:被调用时。 Kind.Line:执行到某行时。 10.其它 1)追踪构造函数用法:@OnMethod(clazz="java.net.ServerSocket",method="<init>”)。 2)追踪静态内部类:在类与内部类之间加上"$"@OnMethod(clazz="com.vip.MyServer$MyInnerClass", method="hello”)。 3)追踪同名函数:如果有多个同名的函数,可以在拦截函数上定义不同的参数列表。 4)追踪结果输出可以使用>将结果输出到指定文件。

 

posted on 2017-05-17 14:38  it_worker365  阅读(323)  评论(0编辑  收藏  举报