当前位置: 首页 > 知识库问答 >
问题:

MethodHandle性能

孔和风
2023-03-14

我编写了一个测试java.lang.Invoke.MethodHandlejava.lang.Reflect.Method和方法直接调用的性能的小基准测试。

我读到methodhandle.invoke()的性能几乎与直接调用相同。但我的测试结果显示了另一种情况:methodhandle调用比反射慢三倍。我的问题是什么?这可能是一些JIT优化的结果吗?

public class Main {
    public static final int COUNT = 100000000;
    static TestInstance test = new TestInstance();

    static void testInvokeDynamic() throws NoSuchMethodException, IllegalAccessException {
        int [] ar = new int[COUNT];

        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType mt = MethodType.methodType(int.class);

        MethodHandle handle = lookup.findStatic(TestInstance.class, "publicStaticMethod", mt) ;

        try {
            long start = System.currentTimeMillis();

            for (int i=0; i<COUNT; i++) {
                ar[i] = (int)handle.invokeExact();
            }

            long stop = System.currentTimeMillis();

            System.out.println(ar);

            System.out.println("InvokeDynamic time: " + (stop - start));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    static void testDirect() {
        int [] ar = new int[COUNT];

        try {
            long start = System.currentTimeMillis();

            for (int i=0; i<COUNT; i++) {
                ar[i] = TestInstance.publicStaticMethod();
            }

            long stop = System.currentTimeMillis();

            System.out.println(ar);

            System.out.println("Direct call time: " + (stop - start));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    static void testReflection() throws NoSuchMethodException {
        int [] ar = new int[COUNT];

        Method method = test.getClass().getMethod("publicStaticMethod");

        try {
            long start = System.currentTimeMillis();

            for (int i=0; i<COUNT; i++) {
                ar[i] = (int)method.invoke(test);
            }

            long stop = System.currentTimeMillis();

            System.out.println(ar);

            System.out.println("Reflection time: " + (stop - start));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    static void testReflectionAccessible() throws NoSuchMethodException {
        int [] ar = new int[COUNT];

        Method method = test.getClass().getMethod("publicStaticMethod");
        method.setAccessible(true);

        try {
            long start = System.currentTimeMillis();

            for (int i=0; i<COUNT; i++) {
                ar[i] = (int)method.invoke(test);
            }

            long stop = System.currentTimeMillis();

            System.out.println(ar);

            System.out.println("Reflection accessible time: " + (stop - start));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    public static void main(String ... args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InterruptedException {
        Thread.sleep(5000);

        Main.testDirect();
        Main.testInvokeDynamic();
        Main.testReflection();
        Main.testReflectionAccessible();

        System.out.println("\n___\n");

        System.gc();
        System.gc();

        Main.testDirect();
        Main.testInvokeDynamic();
        Main.testReflection();
        Main.testReflectionAccessible();
    }
}

环境:java版本“1.7.0_11”java(TM)SE Runtime Environment(build 1.7.0_11-B21)java HotSpot(TM)64位服务器VM(build 23.6-B04,混合模式)OS-Windows 7 64

共有1个答案

高慈
2023-03-14

看起来@AlekseyShipilev在引用另一个查询时间接地回答了这个问题。在下面的链接中,我如何提高field.set(使用MethodHandles的perhap)的性能?

如果通读,您将看到显示类似发现的附加基准。直接调用很可能可以简单地通过JIT优化,根据上面的发现,不同之处在于:

  • MethodHandle.Invoke=~195ns
  • MethodHandle.InvokeExact=~10ns
  • 直接呼叫=1.266 ns

所以--直接通话还是会更快,但MH非常快。对于大多数用例,这应该是足够的,并且肯定比旧的反射框架更快(顺便说一句--根据上面的发现,反射在java8 vm下也要快得多)

如果这种差异在您的系统中很明显,我会建议寻找不同的模式,而不是支持直接调用的直接反射。

 类似资料:
  • 编辑: 这就是我得到的:

  • 问题内容: 我正在研究JDK 1.7的新功能,但我无法了解MethodHandle是为什么设计的?我了解静态方法的(直接)调用(以及在这种情况下简单的Core Reflection API的使用)。我也了解(直接)调用虚拟方法(非静态,非最终)(以及使用需要经过Class层次结构的Core Reflection API )。非虚拟方法的调用可以视为前一种的特殊情况。 是的,我知道重载存在问题。如果

  • 我正在尝试在我的Android应用中使用 SOAP 服务。我正在尝试遵循本指南。当我尝试运行我的应用程序时,我收到一个错误: 我使用的是Android N(SDK 25-我不能像错误消息所示那样跳到26),这是Android Studio刚刚创建的一个全新项目。 这是我的项目构建.gradle文件,我没有改变: 这是我的app build.gradle文件: 从日志中可以看出,导致这种情况的确切

  • 我尝试通过methodhandles将方法链接在一起,其中一些方法来自泛型类型。如果函数返回泛型类型,我必须为MethodType指定Object.Class,但我看不到将其转换回泛型类型参数类型的简单方法。在大多数情况下,这没有问题,因为invoke似乎自动转换它们,但我必须创建mhs,它可以用InvokeExact运行。难道没有简单的方法使用MethodHandles进行强制转换吗? 我的测试

  • Java7引入了MethodHandle类,用于动态执行给定类的方法。据我所知,在JDK的Android端口上没有这样的东西。除了使用标准的反射类之外,是否有任何解决方法可以用来绕过这个问题?

  • 问题内容: 我如何通过获得所有声明的方法?如何获取所有声明的字段? 有什么区别,和 另外,对于使用MethodHandle API for Java devloper的 教程,我将不胜感激。我强调,我是在使用静态类型语言的普通Java上编程的,并且我不是JVM开发人员,尤其是我对整个字节码废话(invokedynamic)不感兴趣。我想弄清楚如何使用此新API代替Java Core API。 编辑