是否曾在 运行 JVM 中调用过此方法
Has this method ever been called inside a running JVM
有没有办法确定是否曾在 运行 JVM 中调用过某个方法。假设我有以下方法信息,我想知道它是否被调用过:
"methodId": {
"className": "InvokerParser",
"filePath": "org/foo/commons/functors/InvokerParserformer.java",
"methodName": "parser"
}
如果应用程序 运行 在 HotSpot JVM 上,可以使用 HotSpot Serviceability Agent 获取有关给定方法的信息。
这是一个工具,可以检查方法是否已在 运行 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);
}
}
类路径中需要 sa-jdi.jar
(附带 JDK 8)。
运行
java -cp $JAVA_HOME/lib/sa-jdi.jar:. CheckMethodCall <pid>
其中 <pid>
是要检查的 Java 进程 ID。
更新
JDK 11+
的类似工具
使用 --add-modules=jdk.hotspot.agent
并导出所有需要的包。
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);
}
}
有没有办法确定是否曾在 运行 JVM 中调用过某个方法。假设我有以下方法信息,我想知道它是否被调用过:
"methodId": {
"className": "InvokerParser",
"filePath": "org/foo/commons/functors/InvokerParserformer.java",
"methodName": "parser"
}
如果应用程序 运行 在 HotSpot JVM 上,可以使用 HotSpot Serviceability Agent 获取有关给定方法的信息。
这是一个工具,可以检查方法是否已在 运行 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);
}
}
类路径中需要 sa-jdi.jar
(附带 JDK 8)。
运行
java -cp $JAVA_HOME/lib/sa-jdi.jar:. CheckMethodCall <pid>
其中 <pid>
是要检查的 Java 进程 ID。
更新
JDK 11+
的类似工具
使用 --add-modules=jdk.hotspot.agent
并导出所有需要的包。
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);
}
}