java - 方法句柄性能

标签 java performance methodhandle

我写了一个小基准来测试 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 运行时环境(内部版本 1.7.0_11-b21)Java HotSpot(TM) 64 位服务器虚拟机(内部版本 23.6-b04,混合模式)操作系统 - Windows 7 64

最佳答案

@AlekseyShipilev 似乎间接回答了另一个问题。 在以下链接中 How can I improve performance of Field.set (perhap using MethodHandles)?

如果通读,您将看到显示类似发现的其他基准。直接调用很可能可以通过 JIT 以如下方式简单地优化 根据上面的发现,区别在于:

  • MethodHandle.invoke =~195ns
  • MethodHandle.invokeExact =~10ns
  • 直接调用 = 1.266ns

所以 - 直接调用仍然会更快,但 MH 非常快。 对于大多数用例,这应该足够了,而且肯定比旧的反射框架更快(顺便说一句——根据上面的发现,反射在 java8 vm 下也明显更快)

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

关于java - 方法句柄性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15621434/

相关文章:

java - 显示标签Struts 2导出不显示PDF

javascript - 膨胀一个javascript文件以使其更大

javascript - 提高 JavaScript 代码性能

multithreading - 混合SIMD指令和多线程时,我会受到性能损失吗?

java - JLabel setIcon 不起作用

java - 编译文件时是否可以选择版本号?

java - 如何在 JavaFX 3D 中制作 vector 图形样式线?

java - 使用 MethodHandle 查找最具体的重载方法

java - 如何在 JDK 6 中使用方法句柄?