如何在 Java 中跟踪方法调用?

Posted

技术标签:

【中文标题】如何在 Java 中跟踪方法调用?【英文标题】:How do I trace methods calls in Java? 【发布时间】:2015-06-05 14:16:26 【问题描述】:

考虑以下两个简单的 Java 类:

第一个例子

class Computer 
    Computer() 
        System.out.println("Constructor of Computer class.");
    
    void On() 
        System.out.println("PC turning on...");
    
    void working() 
        System.out.println("PC working...");
    
    void Off() 
        System.out.println("PC shuting down...");
    
    public static void main(String[] args) 
        Computer my = new Computer();
        Laptop your = new Laptop();
        my.On();
        my.working();
        your.On();
        your.working();
        my.Off();
        your.Off();
   

第二个例子

class Laptop 
    Laptop() 
        System.out.println("Constructor of Laptop class.");
    
    void On() 
        System.out.println("Laptop turning on...");
    
    void working() 
        System.out.println("Laptop working...");
    
    void Off() 
        System.out.println("Laptop shuting down...");
    

程序运行后,如何追踪(1)哪个对象调用了哪个方法(2)以及多少次?

稍微精确一点,我可能有 100 个类和 1000 个对象,每个对象调用 100 个方法。我希望能够跟踪(在我运行程序之后),哪个对象调用了哪个方法以及调用了多少次。

感谢您的任何建议。

【问题讨论】:

您是在询问更复杂或更一般的示例吗?从这个例子中,很明显,因为每个类只有一个实例,并且没有继承。 @DanielNugent 我正在寻找可在任何情况下使用的答案。我可能有 100 个类和 1000 个对象调用每 100 个方法。我希望能够跟踪(在我运行程序之后),哪个对象调用了哪个方法以及多少次。谢谢 - 乔治 @1sand0s 谢谢,我是新来的。我可能对代码格式不太了解。 @1sand0s 我刚刚进行了格式化,现在看起来没问题。感谢您留下 4 个空格的提示。 【参考方案1】:

这会为所有线程中所有对象的每个方法调用打印一行:

Runtime.traceMethodCalls()(Java 9 中已弃用/无操作)

Runtime.traceInstructions(Java 9 中已弃用/无操作)

您可以使用呼叫跟踪器,如  housemd 或  btrace  或  inTrace

对于更复杂的分析,您可以使用如下调用图实用程序之一:

javashot

java-callgraph

(这里有一个关于主题的article

上述不推荐使用的方法将被删除,因为现在有特定于 JVM 的替代方法:

Java Flight Recorder     JDK 7 自 build 56 的一部分。需要商业许可才能在生产中使用 VisualVM                      免费/受欢迎的第三者

这两个工具都非常易于设置和开始收集信息,并且具有漂亮的 GUI 界面。它们附加到正在运行的 JVM 进程,并允许线程快照和各种其他类型的诊断(Visual VM 有很多可用的插件,但如果你想超越默认行为,可能需要一段时间来配置和理解,而JFR 默认配备更多)。

此外,不要低估 JVM 分布式命令行实用程序 ($JAVA_HOME/bin) 的实用性,它可以执行一些易于访问的诊断。

jstack      堆栈跟踪 jmap       内存映射 jstat        JVM 统计监控 jhat         堆分析工具 jdb        调试器 jinfo       java 进程或核心文件配置信息

【讨论】:

请注意,从 Java 9 开始,此方法与 traceInstructions() 一起是 deprecated。 另外,请注意,这些方法不仅已被弃用,而且也变成了无操作,因此用户在迁移到 JDK 9 时应该寻找替代方法。 注意,traceInstructions() 似乎很少工作,即使是旧的 JVM。我尝试了几个(6、7、8),但无济于事。这与许多其他报告相匹配,例如:***.com/a/1025685/7256341【参考方案2】:
$ jdb -classpath ... -sourcepath ... my.App
jdb> stop on my.App.main
jdb> run
jdb> step          <... repeat until get to interesting line...>
jdb> threads
jdb> trace go methods 0x1    <... 0x1 is our main thread ID ...>    
jdb> step
                   <...HERE you get full methods calls trace...>
jdb> quit

【讨论】:

这个答案的repeat until get to interesting line 部分使它成为假的。

以上是关于如何在 Java 中跟踪方法调用?的主要内容,如果未能解决你的问题,请参考以下文章

应该如何跟踪具有继承的 Java 程序?

java是不是有任何机制让VM在不使用javaagent等的情况下跟踪自身的方法调用?

Android 方法调用跟踪

如何找到调用当前方法的方法?

如何从java本机接口调用getStackTrace方法(jni)

如何调用 Fedex 追踪号码查询服务?