【问题标题】:Has this method ever been called inside a running JVM是否曾经在正在运行的 JVM 中调用过此方法
【发布时间】:2019-04-15 22:33:40
【问题描述】:

有没有办法确定是否曾经在运行的 JVM 中调用过某个方法。假设我有以下方法信息,我想知道它是否被调用过:

    "methodId": {
      "className": "InvokerParser",
      "filePath": "org/foo/commons/functors/InvokerParserformer.java",
      "methodName": "parser"
    }

【问题讨论】:

  • 你可以使用 Aspect/J。或者只是在方法中增加一个静态计数器。
  • 除非您使用 profiler,否则没有程序执行的运行跟踪。
  • @ErwinBolwidt 面向方面编程 (AOP) 是一种选择,您是否有示例参考说明如何做到这一点?
  • 代码中的方法是你控制的吗?
  • 是的,我可以控制方法

标签: java jvm coredump


【解决方案1】:

如果应用程序在 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>

&lt;pid&gt; 是要检查的 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);
    }
}

【讨论】:

  • 太好了,谢谢@apangin。这会捕获通过反射加载的类吗?
  • @JauL 是 - 当前在 VM 中加载的任何类。但是注意类名、方法名和方法签名要在JVMS中描述的类文件格式中指定。
  • sa-jdi.jar 似乎只在 JDK 9 之前的版本中可用,并且从那时起就被封装了。有什么方法可以使用这个 API?我只找到了jhsdb 工具
  • @JurajMartinka 我用 JDK 11 版本的工具更新了答案。
  • @apangin 谢谢!以防万一它不明显(如果有人像我一样不熟悉模块系统),这对我来说是使代理 api 可用于类路径上的所有代码的方法:javac --add-modules=jdk.hotspot.agent --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.tools=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.runtime=ALL-UNNAMED" --add-exports "jdk.hotspot.agent/sun.jvm.hotspot.classfile=ALL-UNNAMED" CheckMethodCall.java;通过java 命令运行程序时也是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 2012-10-12
  • 1970-01-01
相关资源
最近更新 更多