首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MethodHandle性能

MethodHandle性能
EN

Stack Overflow用户
提问于 2013-03-25 17:50:46
回答 3查看 7.7K关注 0票数 24

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

我看到MethodHandle.invoke()的性能几乎和直接调用一样。但是我的测试结果显示了另一个:MethodHandle调用比反射慢三倍。我的问题是什么?这可能是一些JIT优化的结果吗?

代码语言:javascript
复制
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运行时环境(build 1.7.0_11-b21) Java HotSpot(TM) 64位服务器VM (build 23.6-b04,混合模式) OS - Windows 7 64

EN

回答 3

Stack Overflow用户

发布于 2015-01-26 18:31:19

看起来,@AlekseyShipilev在引用另一个查询时间接回答了这个问题。在下面的链接How can I improve performance of Field.set (perhap using MethodHandles)?

如果你仔细阅读,你会看到更多的基准,显示类似的结果。很可能,直接调用可以简单地通过JIT优化,根据上面的发现,不同之处在于:

  • MethodHandle.invoke =~195
  • MethodHandle.invokeExact =~10
  • 直接呼叫=1.266

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

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

票数 4
EN

Stack Overflow用户

发布于 2013-04-10 18:53:23

似乎其他人也看到了类似的结果:http://vanillajava.blogspot.com/2011/08/methodhandle-performance-in-java-7.html

这是其他人的:http://andrewtill.blogspot.com/2011/08/using-method-handles.html

我跑了第二个,看到他们差不多一样的速度,甚至修正测试进行热身。但是,我修复了它,所以它不是每次都创建一个args数组。在默认情况下,结果是相同的:方法句柄要快一点。但我计算了10000000 (默认*10),反射速度要快得多。

因此,我建议使用参数进行测试。我想知道MethodHandles是否更有效地处理参数?另外,检查更改计数--有多少次迭代。

@meriton关于这个问题的评论链接到他的工作,看起来很有帮助:Calling a getter in Java though reflection: What's the fastest way to repeatedly call it (performance and scalability wise)?

票数 1
EN

Stack Overflow用户

发布于 2014-02-04 17:13:17

如果publicStaticMethod是一个简单的实现,比如返回一个常量,那么直接调用很有可能是由JIT编译器嵌入的。这在methodHandles中可能是不可能的。

RE http://vanillajava.blogspot.com/2011/08/methodhandle-performance-in-java-7.html示例,正如前面提到的,它的实现不是很好。如果将计算循环中的类型转换更改为int (而不是Integer),则结果更接近于直接方法调用。

在复杂的实现(创建和调用一个返回随机int的未来任务)的情况下,给出了MethodStatic比直接方法慢10%的更接近的基准数。因此,由于JIT优化,您可能会看到性能下降了3倍。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15621434

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档