2013-11-27 69 views

回答

0

嗯,這在很大程度上取決於你想跟蹤哪些代碼量:

  1. 你想知道你的應用程序的類調用Thread.start:然後,你需要儀器應用程序的所有類。
  2. 您是否想知道任何類別在哪裏調用Thread.start,包括那些Java標準API:然後,您需要儀器Thread,但是難以實現。

爲了實現(1)目標,你可以註冊一個Java agent (tutorial attached),將分析的被加載的類的任何方法,並檢查他們的呼叫Thread.start。無論何時您發現這種方法,您都需要爲這些方法添加某種跟蹤機制,例如調用System.out.printlnASM has an excelent tutorial,他們甚至在方法字節碼的章節中提供了一個類似的例子。此外,您可以使用ASMifier來打印出您實際需要實現的代碼。 (2)的目標是難以實現的。爲了做到這一點,你將不得不redefine the class for Thread這可能會導致一些嚴重的麻煩,因爲它是一個系統類。在Thread類中,可以調用Thread.getStackTrace並檢查當前調用堆棧頂部的方法名稱,該調用堆棧由StackTraceElement表示。您將再次必須啓用跟蹤此方法,例如通過調用System.out.println

我會推薦你​​第一個策略,因爲這樣做更容易。此外,根據您運行應用程序的位置,您可能會破壞JDK的使用許可證。

+1

您是否聽說過['new Throwable().getStackTrace()'](http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#getStackTrace())?獲取調用者並不困難(儘管不推薦用於生產代碼)。 – Holger

+0

我其實沒有想到這一點。然而,你不會得到調用者實例的控制權,只能改變它的類型。然後再一次,你可以在調試的時候找到那個實例,所以有可能是使用JNI或者一些API的方法。 –

+0

我更新了我的答案。謝謝你的提示。我嘗試了一下,發現'Thread.getStackTrace'比創建'Throwable'更容易。 –

0

你可以編寫自己的javaagent來轉換所有的方法。它應該搜索java.lang.Thread.start()調用並在它們之前添加日誌記錄。

所以,你應該檢查所有的方法和查找以下字節碼指令:

INVOKEVIRTUAL java/lang/Thread start()V 

和指令之前插入這樣的事情:

GETSTATIC java/lang/System out Ljava/io/PrintStream; 
LDC ${current_method_name_and_desc} 
INVOKEVIRTUAL java/lang/PrintStream println (Ljava/lang/String;)V 
+0

嗨,正如你告訴我有我自己的javaagent,但啓動方法是本地方法,所以如果我做跟蹤的啓動方法,我的jvm崩潰。它正在爲其他方法工作...是以任何其他方式?或使用ASM本機方法不能檢測? –

+0

@RameshSubramanian,你不應該改變'start'方法本身,而是所有其他的調用'start'的方法。我會延長我的答案並展示主要想法。 –

+0

您的信息:'start'不是本地方法,它在本地調用'start0'。因此,在不推薦的情況下,啓動'啓動'會假設成爲可能。 –