我看到我可以像这样打印当前的堆栈跟踪: Get current stack trace in Java
但是我希望每个String.equals
调用跟踪,我不知道怎么做(我不知道自从我使用库以来这些调用的位置)。
我想知道何时调用这些调用来提高代码的性能。
编辑:根据答案的数量,也许我的问题不明确:
我想在我的Java程序中跟踪String.equals()
的每个调用,我不关心该方法。 ;)
答案 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中,热点回溯看起来像这样:
如果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如何让程序告诉你什么需要时间。