?BTrace?是一个非常不错的java诊断工具,?最近试着用了一下,?文档比较少,?主要是看例子吧.??
BTrace?中的B表示bytecode,?表明它是在字节码层面上对代码进行trace?
用来在运行中的java类中注入trace代码,?并对运行中的目标程序进行热交换(hotswap)?
btrace还提供了VisualVM Plugin 以及Netbeans Plugin
术语?
Probe Point?
在何处执行trace语句,?这里的"何处"可以是具体的跟踪地点和执行事件,?在BTrace中通过各种注解来指定?
Trace Actions or Actions?
在何时执行trace语句?
Action Methods?
定义在trace脚本中的trace语句,?具体来说就是脚本中的无返回值静态方法(1.2之后可以是非静态方法)?
BTrace限制?
为了保证trace语句只读, BTrace对trace脚本有一些限制(比如不能改变被trace代码中的状态)?
·?????????BTrace class不能新建类,?新建数组,?抛异常,?捕获异常,
·?????????不能调用实例方法以及静态方法(com.sun.btrace.BTraceUtils除外)
·?????????不能将目标程序和对象赋值给BTrace的实例和静态field
·?????????不能定义外部,?内部,?匿名,?本地类
·?????????不能有同步块和方法
·?????????不能有循环
·?????????不能实现接口,?不能扩展类
·?????????不能使用assert语句,?不能使用class字面值
?
BTrace步骤?
1.取得目标java进程id(pid)?
2.编写BTrace脚本?
3.执行命令行:??btrace <pid> <自己定制的脚本> <输出文件>
eg:btrace 3045PrintExecuteTime.java > time.log?
完整的BTrace命令:?
引用
btrace [-I <include-path>] [-p <port>] [-cp <classpath>] <pid> <btrace-script> [<args>]
?
- -I 没有这个表明跳过预编译
- include-path: 指定用来编译脚本的头文件路径(关于预编译可参考例子ThreadBean.java)
- port : btrace agent端口, 默认是2020
- classpath : 编译所需类路径, 一般是指btrace-client.jar等类所在路径
- pid : java进程id
- btrace-script: btrace脚本, 如果是java文件, 则是未编译, class文件, 则是已编译过的
- args: 传递给btrace脚本的参数, 在脚本中可以通过$(), $length()来获取这些参数(定义在BTraceUtils中)
预编译BTrace脚本命令?
引用
btracec [-I <include-path>] [-cp <classpath>] [-d <directory>] <one-or-more-BTrace-.java-
files>
参数和上面大同小异, btracec 是一个类似javac的程序, 使用该程序编译, 将根据BTrace的限制条件进行严格检查?
在目标程序中启动BTrace Agent?
这个主要针对需要在目标程序启动的时候就需要trace其行为的场景, 此时BTrace agent将与目标程序一起启动(前提是必须对BTrace脚本进行预编译)?
命令行:?
引用
java -javaagent:btrace-agent.jar=script=<pre-compiled-btrace-script1>[,<pre-compiled-btrace-script1>]* <MainClass> <AppArguments>
方法上的注解?
- @com.sun.btrace.annotations.OnMethod? 用来指定trace的目标类和方法以及具体位置, 被注解的方法在匹配的方法执行到指定的位置会被调用. "clazz"属性用来指定目标类名, 可以指定全限定类名, 比如"java.awt.Component", 也可以是正则表达式(表达式必须写在"//"中, 比如"/java\\.awt\\..+/").? "method"属性用来指定被trace的方法. 表达式可以参考自带的例子(NewComponent.java 和 Classload.java, 关于方法的注解可以参考MultiClass.java). 有时候被trace的类和方法可能也使用了注解. 用法参考自带例子WebServiceTracker.java. 针对注解也是可以使用正则表达式, 比如像这个"@/com\\.acme\\..+/ ", 也可以通过指定超类来匹配多个类, 比如"+java.lang.Runnable"可以匹配所有实现了java.lang.Runnable接口的类. 具体参考自带例子SubtypeTracer.java.
- @com.sun.btrace.annotations.OnTimer 用来指定时长(ms)执行一次trace. 时长通过"value"属性指定. 具体参考自带例子 Histogram.java
- @com.sun.btrace.annotations.OnError 当trace代码抛异常时该注解的方法会被执行. 如果同一个trace脚本中其他方法抛异常, 该注解方法也会被执行.
- @com.sun.btrace.annotations.OnExit 当trace方法调用内置exit(int)方法(用来结束整个trace程序)时, 该注解的方法会被执行. 参考自带例子ProbeExit.java.
- @com.sun.btrace.annotations.OnEvent 用来截获"外部"btrace client触发的事件, 比如按Ctrl-C 中断btrace执行时将执行使用了该注解的方法, 该注解的value值为具体事件名称. 具体参考例子HistoOnEvent.java
- @com.sun.btrace.annotations.OnLowMemory 当内存超过某个设定值将触发该注解的方法, 具体参考MemAlerter.java
- @com.sun.btrace.annotations.OnProbe //我也没搞明白:(
参数上的注解?
- @com.sun.btrace.annotations.Self 用来指定被trace方法的this, 可参考例子AWTEventTracer.java 和 AllCalls1.java
- @com.sun.btrace.annotations.Return 用来指定被trace方法的返回值, 可参考例子Classload.java
- @com.sun.btrace.annotations.ProbeClassName (since 1.1) 用来指定被trace的类名, 可参考例子AllMethods.java
- @com.sun.btrace.annotations.ProbeMethodName (since 1.1) 用来指定被trace的方法名, 可参考例子WebServiceTracker.java
????????? o (since 1.2)可以通过注解的fqn boolean属性来表明是否要获取全限定方法名?
?
- @com.sun.btrace.annotations.TargetInstance (since 1.1) 用来指定被trace方法内部被调用到的实例, 可参考例子AllCalls2.java
- @com.sun.btrace.annotations.TargetMethodOrField (since 1.1) 用来指定被trace方法内部被调用的方法名, 可参考例子AllCalls1.java 合 AllCalls2.java
????????? o (since 1.2) 可通过注解的fqn boolean属性来表明是否要获取全限定方法名?
未被注解的方法参数?
未使用注解的方法参数一般都是用来做方法签名匹配用的, 他们一般和被trace方法中参数出现的顺序一致. 不过他们也可以与注解方法交错使用, 如果一个参数类型声明为*AnyType[]*, 则表明它按顺序"通吃"方法所有参数. 未注解方法需要与*Location*结合使用:?
- Kind.ENTRY, Kind.RETURN- 被trace方法参数
- Kind.THROW - 抛异常
- Kind.ARRAY_SET, Kind.ARRAY_GET - 数组索引
- Kind.CATCH - 捕获异常
- Kind.FIELD_SET - 属性值
- Kind.LINE - 行号
- Kind.NEW - 类名
- Kind.ERROR - 抛异常
属性上的注解?
- @com.sun.btrace.annotations.Export 该注解的静态属性主要用来与jvmstat计数器做关联. 使用该注解之后, btrace程序就可以向jvmstat客户端(可以用来统计jvm堆中的内存使用量)暴露trace程序的执行次数, 具体可参考例子ThreadCounter.java
- @com.sun.btrace.annotations.Property 使用了该注解的trace脚本将作为MBean的一个属性, 一旦使用该注解, trace脚本就会创建一个MBean并向MBean服务器注册, 这样JMX客户端比如VisualVM, jconsole就可以看到这些BTrace MBean. 如果这些被注解的属性与被trace程序的属性关联, 那么就可以通过VisualVM 和jconsole来查看这些属性了. 具体可参考例子ThreadCounterBean.java 和 HistogramBean.java.
- @com.sun.btrace.annotations.TLS 用来将一个脚本变量与一个ThreadLocal变量关联. 因为ThreadLocal变量是跟线程相关的, 一般用来检查在同一个线程调用中是否执行到了被trace的方法. 具体可参考例子OnThrow.java 和 WebServiceTracker.java
类上的注解?
- @com.sun.btrace.annotations.DTrace 用来指定btrace脚本与内置在其脚本中的D语言脚本关联, 具体参考例子DTraceInline.java.
- @com.sun.btrace.annotations.DTraceRef 用来指定btrace脚本与另一个D语言脚本文件关联. 具体参考例子DTraceRefDemo.java.
- @com.sun.btrace.annotations.BTrace 用来指定该java类为一个btrace脚本文件.
监控方法参数(数组)
?1?????
import?
static?com.sun.btrace.BTraceUtils.print;????
?2?????
import?
static?com.sun.btrace.BTraceUtils.printArray;????
?3?????
import?
static?com.sun.btrace.BTraceUtils.println;????
?4?????
import?
static?com.sun.btrace.BTraceUtils.probeClass;????
?5?????
import?
static?com.sun.btrace.BTraceUtils.probeMethod;????
?6????????
?7?????
import?com.sun.btrace.annotations.BTrace;????
?8?????
import?com.sun.btrace.annotations.OnMethod;????
?9????????
10?????@BTrace???
11?????
public?
class?PrintArgArray?{????
12????????
13?????????
/**?
14?
??????????*?此方法打印出Test类中的mergeArray(Long[]?arrayOne,?Long[]?arrayTwo)方法传入的参数?
15?
??????????*?参数名字一定要和监控对象的方法参数名字一致?
16?
??????????*?
17?
??????????*?@param?arrayOne?监控参数一?
18?
??????????*?@param?arrayTwo?监控参数二?
19?
??????????*?
20?
??????????*/???
21?????????@OnMethod(clazz?=?"com.jerry.test.Test",?method?=?"mergeArray")????
22?????????
//?此处写明要监控的包、类、方法等???可以使用正则匹配????
23?????????
public?
static?
void?anyRead(Long[]?arrayOne,?Long[]?arrayTwo)?{????
24?????????????
//?打印监控的类名????
25??????????????print(probeClass());????
26??????????????print("???[");????
27?????????????
//?打印监控的方法名????
28??????????????print(probeMethod());????
29??????????????println("]");????
30????????
31?????????????
if?(arrayOne?!=?
null)?{????
32??????????????????printArray(arrayOne);????
33??????????????}?
else?{????
34??????????????????println("the?arguments?is?null!");????
35??????????????}????
36????????
37?????????????
if?(arrayTwo?!=?
null)?{????
38??????????????????printArray(arrayTwo);????
39??????????????}?
else?{????
40??????????????????println("the?arguments?is?null!");????
41??????????????}????
42??????????}????
43????????
44?????}???
监控使用时间
?1?????
import?
static?com.sun.btrace.BTraceUtils.name;????
?2?????
import?
static?com.sun.btrace.BTraceUtils.print;????
?3?????
import?
static?com.sun.btrace.BTraceUtils.println;????
?4?????
import?
static?com.sun.btrace.BTraceUtils.probeClass;????
?5?????
import?
static?com.sun.btrace.BTraceUtils.probeMethod;????
?6?????
import?
static?com.sun.btrace.BTraceUtils.str;????
?7?????
import?
static?com.sun.btrace.BTraceUtils.strcat;????
?8?????
import?
static?com.sun.btrace.BTraceUtils.timeMillis;????
?9????????
10?????
import?com.sun.btrace.annotations.BTrace;????
11?????
import?com.sun.btrace.annotations.Kind;????
12?????
import?com.sun.btrace.annotations.Location;????
13?????
import?com.sun.btrace.annotations.OnMethod;????
14?????
import?com.sun.btrace.annotations.TLS;????
15????????
16?????
/**?
17?
????*?监控方法耗时?
18?
????*?
19?
????*?
20?
????*/???
21?????@BTrace???
22?????
public?
class?PrintTimes?{????
23????????
24?????????
/**?
25?
??????????*?开始时间?
26?
??????????*/???
27?????????@TLS???
28?????????
private?
static?
long?startTime?=?0;????
29????????
30?????????
/**?
31?
??????????*?方法开始时调用?
32?
??????????*/???
33?????????@OnMethod(clazz?=?"/com\\copul\\../",?method?=?"/.+/")????
34?????????
public?
static?
void?startMethod()?{????
35??????????????startTime?=?timeMillis();????
36??????????}????
37????????
38?????????
/**?
39?
??????????*?方法结束时调用<br>?
40?
??????????*?Kind.RETURN这个注解很重要?
41?
??????????*/???
42?????????@SuppressWarnings("deprecation")????
43?????????@OnMethod(clazz?=?"/com\\.copul\\../",?method?=?"/.+/",?location?=?@Location(Kind.RETURN))????
44?????????
public?
static?
void?endMethod()?{????
45????????
46??????????????print(strcat(strcat(name(probeClass()),?"."),?probeMethod()));????
47??????????????print("???[");????
48??????????????print(strcat("Time?taken?:?",?str(timeMillis()?-?startTime)));????
49??????????????println("]");????
50??????????}????
51?????}???
监控内存
?1?????
import?
static?com.sun.btrace.BTraceUtils.*;????
?2?????
import?java.lang.management.Memory
Usage;????
?3????????
?4?????
import?com.sun.btrace.annotations.BTrace;????
?5?????
import?com.sun.btrace.annotations.OnLowMemory;????
?6????????
?7?????
/**?
?8?
????*?监控内存使用?
?9?
????*?
10?
????*?
11?
????*/???
12?????@BTrace???
13?????
public?
class?PrintMemory?{????
14????????
15?????????
/*?
16?
??????????*?指定内存区域低于一定的界限的时候才内存使用打印数据<br>?也可以指定时间间隔打印内存使用?
17?
??????????*/???
18?????????@OnLowMemory(pool?=?"
Tenured?Gen",?threshold?=?6000000)????
19?????????
public?
static?
void?printMem(MemoryUsage?mu)?{????
20??????????????print("MemoryUsage?:?");????
21??????????????println(mu);????
22??????????????print("FreeMem?:?");????
23??????????????println(freeMemory());????
24??????????????print("Heap:");????
25??????????????println(heapUsage());????
26??????????????print("Non-Heap:");????
27??????????????println(nonHeapUsage());????
28??????????}????
29?????}