1.美图
2.概述
在生产环境中经常遇到格式各样的问题,如OOM或者莫名其妙的进程死掉。一般情况下是通过修改程序,添加打印日志;然后重新发布程序来完成。然而,这不仅麻烦,而且带来很多不可控的因素。有没有一种方式,在不修改原有运行程序的情况下获取运行时的数据信息呢?如方法参数、返回值、全局变量、堆栈信息等。Btrace就是这样一个工具,它可以在不修改原有代码的情况下动态地追踪java运行程序,通过hotswap技术,动态将跟踪字节码注入到运行类中,对运行代码侵入较小,对性能上的影响可以忽略不计。
在下列情况时可以使用BTrace进行分析:
-
接口性能变慢,分析每个方法的耗时情况;
-
当在Map中插入大量数据,分析其扩容情况;
-
分析哪个方法调用了System.gc(),调用栈如何;
-
执行某个方法抛出异常时,分析运行时参数;
-
…
3. 使用场景
- 服务慢,能找出慢在哪一步,哪个函数里么?
- 谁构造了一个超大的ArrayList?
- 什么样的入参或对象属性,导致抛出了这个异常?或进入了这个处理分支?
4.限制
为了避免Btrace脚本的消耗过大影响真正业务,所以定义了一系列不允许的事情:比如不允许调用任何类的任何方法,只能调用BTraceUtils 里的一系列方法和脚本里定义的static方法。 比如不允许创建对象,比如不允许For 循环等等,更多规定看User Guide
5.基本命令
./btrace $pid HelloWorld.java
./btrace -o mylog.log $pid HelloWorld.java
很坑新人的参数,首先,这个mylog会生成在应用的启动目录,而不是btrace的启动目录。其次,执行过一次-o之后,再执行btrace不加-o 也不会再输出回console,直到应用重启为止。
./btrace $pid HelloWorld.java > mylog.log
预编译脚本
./btracec HelloWorld.java
6.BTrace使用
下面是测试类,我是在IDEA中测试运行的
package com.java.book.jvm.chapter4;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author zzm
*/
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));
}
}
}
切记先运行以上程序,然后打开jvisualvm.exe
,会看见运行那个程序的进程,右击那个进程点击“Trace Application...
”就会出现以下面板
界面如下
在右边面板中放入
@OnMethod(
clazz = "logback.BTraceTest",
method = "add",
location = @Location(Kind.RETURN)
)
public static void func(@Self logback.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”,
但是我的报错
错误详情如下
* Starting BTrace task
** Compiling the BTrace script ...
/TracingScript.java:13: 错误: 程序包logback不存在
public static void func(@Self logback.BTraceTest instance,int a,int b,@Return int result){
^
!!! Error occured
!!! Error occured
还没找到原因。后来发现实代码有问题
/* 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.java.book.jvm.chapter4.BTraceTest",
method = "add",
location = @Location(Kind.RETURN)
)
public static void func(@Self com.java.book.jvm.chapter4.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)));
}
}
改成这个样子就好了。
正常的,然后再console中回车,执行方法
然后就能在BTrace中看到运行结果了