获取String.equals调用跟踪

时间:2017-10-24 17:10:11

标签: java profiling stack-trace backtrace

我看到我可以像这样打印当前的堆栈跟踪: Get current stack trace in Java

但是我希望每个String.equals调用跟踪,我不知道怎么做(我不知道自从我使用库以来这些调用的位置)。

我想知道何时调用这些调用来提高代码的性能。

编辑:根据答案的数量,也许我的问题不明确: 我想在我的Java程序中跟踪String.equals()的每个调用,我不关心该方法。 ;)

4 个答案:

答案 0 :(得分:2)

我非常怀疑这是由许多JVM支持的。拦截每个方法调用的一种可能方法是使用Java Instrumentation API设置字节码。

问题是类主要可以在加载类的时刻进行检测。因此,虽然我建议的方法适用于您的应用程序类,但{J}已预先加载String类。要修改加载的类,JVM应支持类retransform或类redefine。您可以使用下一个简单的Maven项目来检查:

的pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.stackoverflow.questions</groupId>
    <artifactId>stringequalscall</artifactId>
    <version>0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <PreMain-Class>com.stackoverflow.questions.stringequalscall.Agent</PreMain-Class>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

的src /主/ JAVA / COM /计算器/问题/ stringequalscall / Agent.java:

package com.stackoverflow.questions.stringequalscall;

import java.lang.instrument.Instrumentation;

public class Agent {

    public static void premain(String args, Instrumentation instrumentation) {
        System.out.println("Can redefine classes: " + instrumentation.isRedefineClassesSupported());
        System.out.println("Can retransform classes: " + instrumentation.isRetransformClassesSupported());
        System.out.println("String modifiable: " + instrumentation.isModifiableClass(String.class));
    }
}

的src /主/ JAVA / COM /计算器/问题/ stringequalscall / AgentTest.java:

package com.stackoverflow.questions.stringequalscall;

public class AgentTest {

    public static void main(String[] args) {
        System.out.println("Executing Agent test");
    }
}

构建JAR:

mvn clean install

从您的target文件夹中运行

java -javaagent:stringequalscall-0.1-SNAPSHOT.jar com.stackoverflow.questions.stringequalscall.AgentTest

如果JVM支持上述加载的类操作方法之一,那么您可以尝试编写自己的Java代理,以便将执行跟踪添加到String#equals(String)

对于我在Oracle Java 9上的输出是:

Can redefine classes: false
Can retransform classes: false
String modifiable: true
Executing Agent test

BTW为什么你认为String#equals(String)可能是你性能问题的根源?

P.S。至少编写简单的Java代理很有趣。

答案 1 :(得分:1)

我建议使用分析器。大多数个人资料提供了一个热点&#34;查看您将看到String.equals方法的位置并打开其回溯,以查看方法调用的来源。

与隔离测量相比,另一个优势是您可以评估其与其他热点的相对重要性。

例如在JProfiler中,热点回溯看起来像这样:

enter image description here

如果String.equals不是热点,您可以将底部的视图过滤器设置为java.lang.String,以查看String类的所有记录方法。

免责声明:我公司开发JProfiler

答案 2 :(得分:0)

java.lang.Runtime.traceMethodCalls(boolean on)方法启用/禁用方法调用的跟踪。

以下示例显示了lang.Runtime.traceMethodCalls()方法的用法。

            public class RuntimeDemo {

               public static void main(String[] args) {

                  // print the state of the program
                  System.out.println("Program is starting...");

                  // start tracing for instructions
                  System.out.println("Enabling tracing...");
                  Runtime.getRuntime().traceMethodCalls(true);
                  System.out.println("Done!");
               }
            }

编译并运行上面的程序,这将产生以下结果 -

计划正在开始......

启用跟踪......

完成!

这是用于跟踪所有方法,我将针对特定方法进行更新。

你也可以尝试这个:jcabi-aspects - 记录Java方法执行

使用@Loggable注释注释您的方法,每次调用它们时,您的SLF4J日志记录工具都会收到一条消息,其中包含执行细节和总执行时间:

            public class Resource {
              @Loggable(Loggable.DEBUG)
              public String load(URL url) {
                return url.openConnection().getContent();
              }
            }

这样的东西会出现在日志中:

[DEBUG] #load(&#39; http://www.google.com&#39;):返回&#34;

答案 3 :(得分:0)

你正在做出一个假设。你假设String.equals是一个主要的时间窃取者。

性能分析的关键是不要提前做出任何假设, 因为那时你是盲目的让程序告诉你什么需要时间,这可能是你的想法,但可能是其他东西

Here's a simple example如何让程序告诉你什么需要时间。