2013-11-27 137 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'。因此,在不推荐的情况下,启动'启动'会假设成为可能。 –