Java 在运行的JVM中是否调用过此方法
有没有办法确定在运行JVM的内部是否调用过方法。假设我有以下方法信息,我想知道它是否被调用过:Java 在运行的JVM中是否调用过此方法,java,jvm,coredump,Java,Jvm,Coredump,有没有办法确定在运行JVM的内部是否调用过方法。假设我有以下方法信息,我想知道它是否被调用过: "methodId": { "className": "InvokerParser", "filePath": "org/foo/commons/functors/InvokerParserformer.java", "methodName": "parser" } 如果应用程序在HotSpot JVM上运行,则可以使用HotSpot服务性代理获取
"methodId": {
"className": "InvokerParser",
"filePath": "org/foo/commons/functors/InvokerParserformer.java",
"methodName": "parser"
}
如果应用程序在HotSpot JVM上运行,则可以使用HotSpot服务性代理获取有关给定方法的信息 下面是一个工具,用于检查该方法是否已在运行的JVM中被调用
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Method;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;
public class CheckMethodCall extends Tool {
private static final String className = "java/util/HashMap";
private static final String methodName = "get";
private static final String methodSig = "(Ljava/lang/Object;)Ljava/lang/Object;";
@Override
public void run() {
boolean[] result = new boolean[2];
VM.getVM().getSystemDictionary().classesDo(klass -> {
if (klass.getName().asString().equals(className)) {
Method method = ((InstanceKlass) klass).findMethod(methodName, methodSig);
if (method != null) {
result[0] = true;
result[1] = method.getMethodCounters() != null &&
method.getInvocationCount() + method.interpreterInvocationCount() > 0;
}
}
});
if (!result[0]) {
System.out.println("Method not found");
} else if (result[1]) {
System.out.println("Method has been called");
} else {
System.out.println("Method has NOT been called");
}
}
public static void main(String[] args) {
new CheckMethodCall().execute(args);
}
}
它需要类路径中的sajdi.jar
(随JDK8提供)
跑
您可以使用Aspect/J。或者只是在方法中增加一个静态计数器。除非您使用探查器,否则不会有程序执行的运行跟踪。@ErwinBolwidt面向方面编程(AOP)是一个选项,您有如何实现这一点的示例参考吗?您可以控制代码中的方法吗?是的,我可以控制该方法很好,谢谢@apangin。这会捕获通过反射加载的类吗?@JauL Yes-VM中当前加载的任何类。但是请注意,类名、方法名和方法签名应该以JVM中描述的类文件格式指定。似乎
sa jdi.jar
只在JDK 9之前的版本中可用,并且从那时起就被封装了。有什么方法可以使用这个API吗?我只找到了jhsdb
tool@JurajMartinka我用JDK 11版本的工具更新了答案。@apangin谢谢!以防万一(如果有人和我一样不熟悉模块系统),这就是使代理api对类路径上的所有代码可用的原因:javac--add modules=jdk.hosts.agent--add exports“jdk.hosts.agent/sun.jvm.hosts.oops=all-UNNAMED”-add exports“jdk.hospot.agent/sun.jvm.hospot.tools=ALL-UNNAMED”--添加导出“jdk.hospot.agent/sun.jvm.hospot.runtime=ALL-UNNAMED”--添加导出“jdk.hospot.agent/sun.jvm.hospot.classfile=ALL-UNNAMED”CheckMethodCall.java
;通过java
命令运行程序时也是如此。
java -cp $JAVA_HOME/lib/sa-jdi.jar:. CheckMethodCall <pid>
import sun.jvm.hotspot.oops.InstanceKlass;
import sun.jvm.hotspot.oops.Klass;
import sun.jvm.hotspot.oops.Method;
import sun.jvm.hotspot.runtime.VM;
import sun.jvm.hotspot.tools.Tool;
public class CheckMethodCall extends Tool {
private static final String className = "java/util/HashMap";
private static final String methodName = "get";
private static final String methodSig = "(Ljava/lang/Object;)Ljava/lang/Object;";
@Override
public void run() {
Klass klass = VM.getVM().getClassLoaderDataGraph().find(className);
if (klass == null) {
System.out.println("Class not found");
return;
}
Method method = ((InstanceKlass) klass).findMethod(methodName, methodSig);
if (method == null) {
System.out.println("Method not found");
return;
}
boolean called = method.getMethodCounters() != null &&
method.getInvocationCount() + method.interpreterInvocationCount() > 0;
System.out.println("Method " + (called ? "has been" : "has NOT been") + " called");
}
public static void main(String[] args) {
new CheckMethodCall().execute(args);
}
}