在生産環境中經常遇到格式各樣的問題,如OOM或者莫名其妙的程序死掉。一般情況下是通過修改程式,添加列印日志;然後重新釋出程式來完成。然而,這不僅麻煩,而且帶來很多不可控的因素。有沒有一種方式,在不修改原有運作程式的情況下擷取運作時的資料資訊呢?如方法參數、傳回值、全局變量、堆棧資訊等。Btrace就是這樣一個工具,它可以在不修改原有代碼的情況下動态地追蹤java運作程式,通過hotswap技術,動态将跟蹤位元組碼注入到運作類中,對運作代碼侵入較小,對性能上的影響可以忽略不計。
基礎說明
由于Btrace會把腳本邏輯直接侵入到運作的代碼中,是以在使用上做很多限制:
不能建立對象
不能使用數組
不能抛出或捕獲異常
不能使用循環
不能使用synchronized關鍵字
屬性和方法必須使用static修飾
需要特别注意的是:不恰當的使用BTrace可能導緻JVM崩潰,如在BTrace腳本使用錯誤的class檔案,是以在上生産環境之前,務必在本地充分的驗證腳本的正确性。
Btrace可以做什麼?
接口性能變慢,分析每個方法的耗時情況;
當在Map中插入大量資料,分析其擴容情況;
分析哪個方法調用了System.gc(),調用棧如何;
執行某個方法抛出異常時,分析運作時參數;
....
參數說明:
指定分析方法的入口:@OnMethod
Btrace使用@OnMethod注解定義需要分析的方法入口
在@OnMethod注解中,需要指定class、method以及location等,class表明需要監控的類,method表明需要監控的方法,指定方式如下:
使用全限定名:clazz="com.metty.rpc.common.BtraceCase", method="add"
使用正規表達式:clazz="/javax.swing../", method="/./"
使用接口:clazz="+com.ctrip.demo.Filter", method="doFilter"
使用注解:clazz="@javax.jws.WebService", method=""@javax.jws.WebMethod"
如果需要分析構造方法,需要指定method=""
指定方法攔截的位置:@Location
定義Btrace對方法的攔截位置,通過@Location注解指定,預設為Kind.ENTRY
Kind.ENTRY:在進入方法時,調用Btrace腳本
Kind.RETURN:方法執行完時,調用Btrace腳本,隻有把攔截位置定義為Kind.RETURN,才能擷取方法的傳回結果@Return和執行時間@Duration
Kind.CALL:分析方法中調用其它方法的執行情況,比如在execute方法中,想擷取add方法的執行耗時,必須把where設定成Where.AFTER
Kind.LINE:通過設定line,可以監控代碼是否執行到指定的位置
Kind.ERROR, Kind.THROW, Kind.CATCH
總結
Btrace能做的事情太多,但使用之前切記檢查腳本的可行性,一旦Btrace腳本侵入到系統中,隻有通過重新開機才能恢複。
通過jvisualvm插件的方式進行測試:
安裝Btrace插件
工具-->插件-->可用插件中找到BTrace Workbench進行安裝即可。
測試用例
package com.vmtools;
public class Counter {
// 總數
private static int totalCount = 0;
public int add(int num) throws Exception {
totalCount += num;
sleep();
return totalCount;
}
private void sleep() throws InterruptedException {
Thread.sleep(1000);
}
import java.util.Random;
public class BtraceTest {
public static void main(String[] args) throws Exception {
Random random = new Random();
// 計數器
Counter counter = new Counter();
while (true) {
// 每次增加随機值
counter.add(random.nextInt(10));
Thread.sleep(1000);
}
Btrace測試
運作上訴測試用例
jvisualvm中找到對應的程序id-->Trace application...-->分别進行相應的測試
擷取add()方法參數值和傳回值。
/* BTrace Script Template */
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
//擷取add()方法參數值和傳回值。
@BTrace
public class TracingScript {
/* put your code here */
@OnMethod(
clazz="com.vmtools.Counter",
method="add",
location=@Location(Kind.RETURN)
)
public static void func(
int a,
@Return int result) {
println("trace: =======================");
jstack();
println(strcat("a:", str(a)));
println(strcat("result:", str(result)));
定時擷取Counter類的屬性值totalCount
//定時擷取Counter類的屬性值totalCount。
private static Object totalCount=0;
public static void func(@Self com.vmtools.Counter counter) {
totalCount = get(field("com.vmtools.Counter", "totalCount"), counter);
@OnTimer(2000)
public static void print(){
println(" ====== ");
println(strcat("totalCount: ",str(totalCount)));
擷取add方法執行時間
//擷取add方法執行時間
@TLS private static long startTime = 0;
method="add"
startTime = timeNanos();
public static void endExecute(@Duration long duration){
long time = timeNanos() - startTime;
println(strcat("execute time(nanos): ", str(time)));
println(strcat("duration(nanos): ", str(duration)));
}
本文轉自秋楓部落格園部落格,原文連結:http://www.cnblogs.com/rwxwsblog/p/6248210.html,如需轉載請自行聯系原作者