blog.Ring.idv.tw

BTrace - A Dynamic Tracing Tool for Java

BTrace - A Dynamic Tracing Tool for Java

BTrace 是一套可以讓你動態追踨(trace)運作中程式的工具,它是由當時Sun公司的兩位高級工程師(Staff Engineer)Sundararajan AthijegannathanKannan Balasubramanian,在2007年開始進行的一項計劃,並於2008年在JavaOne的會議上正式對外公開:BTrace: Java™ Platform Observability by Bytecode Instrumentation (pdf),不過隨著Oracle在2010年併購Sun之後,目前只有A. Sundararajan仍然在Oracle公司服務,而B. Kannan則是在VMWare服務。

那究竟BTrace有何過人之處呢?舉個實例來說,以往要評估一個method會耗多少執行時間,可能的寫法如下:

long start = System.nanoTime();
test();
long end = System.nanoTime();
System.out.println(end - start);

但這樣的作法在小程式還可行,倘若要用來追踨一些大型Project原始碼的話就太麻煩了...Orz

雖然還有另一種方法,就是用JDK 5所提供的java.lang.instrument API來達成,透過AOP的方式在class載入之前就注入(inject)一些bytecode,如此便能無須更動原始碼即可完成所需,但這若是面對一個正在「運作中的程式(running program)」仍有些麻煩,除非透過JVM Tool Interface (JVM TI)的技術去達成,不過採用JVM TI還要寫一些native code,這實在還是不夠方便... 而就在2006年底時JDK 6(Mustang)正式推出之後,它為Java帶來了一些新的API,如:Java Attach APIJava Compiler API等。

簡單來說,透過Java Attach API不像JVM TI技術需要寫些native code,它就能藉由VirtualMachine class用純Java的方式去attach to a JVM,如:

VirtualMachine vm = VirtualMachine.attach(processid);
String agent = ...
vm.loadAgent(agent);

也正因為如此,所以BTrace是一個結合Java Attach APIJava Compiler APIJava Instrumentation APIASM (A Java bytecode engineering library)等技術來實現的,而這些關鍵API對應BTrace的原始碼如下:

Java Attach API: net.java.btrace.client.Client.java

Java Compiler API: net.java.btrace.compiler.Compiler.java

Java Instrumentation API: net.java.btrace.agen.Main.java

ASM: net.java.btrace.instr.Instrumentor.java

P.S. The ASM name does not mean anything, it's just a reference to the __asm__ keyword in C. (ASM 4.0 A Java bytecode engineering library)

這裡我們來看一個實際的例子,如下述程式:

Hello.java

import java.util.*;

public class Hello
{
    public Hello(){}
    public void sayHello()throws Exception
    {
        Random random = new Random();
        int r = random.nextInt(1000);
        Thread.sleep(r);
        System.out.println("Hello: "+r);
    }
    public static void main(String args[])
    {
        Hello h = new Hello();
        try
        {
            while(true)
            {
                Thread.sleep(1000l);
                h.sayHello();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

接下來~ 假設我們想知道上述程式sayHello method耗多少執行時間或stack trace都可藉由BTrace來完成,如下:

HelloTest.java

import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
 
@BTrace public class HelloTest
{
    @OnMethod(clazz="Hello",method="sayHello")
    public static void trace()
    {
        jstack();
    }
    @OnMethod(clazz="Hello",method="sayHello",location=@Location(value=Kind.RETURN))
    public static void func(@Duration long duration)
    {
        println(duration);
    }
}

上述annotations的詳細用法及BTrace的使用限制可參考BTrace User's Guide

執行BTrace

$BTRACE_HOME/bin/btrace [pid] HelloTest.java

P.S. [pid]可透過「jps」指令來取得。

結果

Hello.sayHello(Hello.java)
Hello.main(Hello.java:21)
803517667
Hello.sayHello(Hello.java)
Hello.main(Hello.java:21)
681229152

相關資源

BTrace Developer's Guide

BTrace – a Simple Way to Instrument Running Java Applications

btrace一些你不知道的事

btrace记忆

Java 動態程式碼變更 (一)

2013-01-08 01:56:18

Leave a Comment

Copyright (C) Ching-Shen Chen. All rights reserved.

::: 搜尋 :::

::: 分類 :::

::: 最新文章 :::

::: 最新回應 :::

::: 訂閱 :::

Atom feed
Atom Comment