简体   繁体   English

方法处理性能

[英]MethodHandle performance

I wrote a little benchmark that tests performance of java.lang.invoke.MethodHandle , java.lang.reflect.Method and direct calls of methods.我写了一个小基准测试java.lang.invoke.MethodHandlejava.lang.reflect.Method和方法的直接调用的性能。

I read that MethodHandle.invoke() performance almost the same as direct calls.我读到MethodHandle.invoke()性能几乎与直接调用相同。 But my test results show another: MethodHandle invoke about three times slower than reflection.但我的测试结果显示另一个: MethodHandle调用比反射慢大约三倍。 What is my problem?我的问题是什么? May be this is result of some JIT optimisations?这可能是一些 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();
    }
}

Environment: java version "1.7.0_11" Java(TM) SE Runtime Environment (build 1.7.0_11-b21) Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode) OS - Windows 7 64环境: Java 版本“1.7.0_11”Java(TM) SE 运行时环境(构建 1.7.0_11-b21)Java HotSpot(TM) 64 位服务器 VM(构建 23.6-b04,混合模式)操作系统 - Windows 7 64

Looks like this was indirectly answered by @AlekseyShipilev in reference to a different query.看起来这是@AlekseyShipilev 参考不同查询间接回答的。 In the following link How can I improve performance of Field.set (perhap using MethodHandles)?在以下链接中, 如何提高 Field.set 的性能(可能使用 MethodHandles)?

If you read through you will see additional benchmarks that show similar findings.如果您通读一遍,您将看到显示类似结果的其他基准测试。 It is likely that direct calls can simply be optimized by JIT in ways that According to the findings above, the difference is:很可能直接调用可以简单地通过 JIT 进行优化,根据上述发现,不同之处在于:

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

So - direct calls will still be faster, but MH is very fast.所以 - 直接呼叫仍然会更快,但 MH 非常快。 For most use-cases this should be sufficient and is certainly faster than the old reflection framework (btw - according to the findings above, reflection is also significantly faster under java8 vm)对于大多数用例,这应该足够了,并且肯定比旧的反射框架更快(顺便说一句 - 根据上面的发现,在 java8 vm 下反射也明显更快)

If this difference is significant in your system, i would suggest finding different patterns rather than direct reflection which will support direct calls.如果这种差异在您的系统中很重要,我建议您寻找不同的模式,而不是直接反射,后者将支持直接调用。

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

Here's someone else's: http://andrewtill.blogspot.com/2011/08/using-method-handles.html这是别人的: http : //andrewtill.blogspot.com/2011/08/using-method-handles.html

I ran that second one and saw they were about the same speed even fixing that test to have a warmup.我跑了第二个,看到它们的速度几乎相同,甚至修复了那个测试以进行热身。 However, I fixed it so it wasn't creating an args array every time.但是,我修复了它,因此它不会每次都创建一个 args 数组。 At the default count, it resulted in the same result: methodhandles were a little faster.在默认计数下,它产生了相同的结果:方法句柄快了一点。 But I did a count of 10000000 (default*10) and reflection went much faster.但是我计算了 10000000(默认值*10),反射速度要快得多。

So, I would recommend testing with parameters.因此,我建议使用参数进行测试。 I wonder if MethodHandles more efficiently deal with parameters?我想知道 MethodHandles 是否更有效地处理参数? Also, check changing the count--how many iterations.此外,检查更改计数 - 多少次迭代。

@meriton's comment on the question links to his work and looks very helpful: Calling a getter in Java though reflection: What's the fastest way to repeatedly call it (performance and scalability wise)? @meriton 对这个问题的评论链接到他的工作,看起来非常有帮助: 通过反射在 Java 中调用 getter:重复调用它的最快方法是什么(性能和可扩展性明智)?

If the publicStaticMethod was a simple implementation like returning a constant, It is very much possible that direct call was in-lined by JIT compiler.如果publicStaticMethod是一个简单的实现,比如返回一个常量,那么直接调用很有可能是由 JIT 编译器内联的。 This may not be possible with methodHandles.这对于 methodHandles 可能是不可能的。

RE http://vanillajava.blogspot.com/2011/08/methodhandle-performance-in-java-7.html example, as mentioned that comments its not great implementation. RE http://vanillajava.blogspot.com/2011/08/methodhandle-performance-in-java-7.html示例,如前所述,评论它的实现并不好。 if you change the type casting to int (instead of Integer) in the calculation loop, the results are closer to direct method call.如果在计算循环中将类型转换更改为 int(而不是 Integer),则结果更接近于直接方法调用。

With convoluted implementation of ( creating and calling a future task which returns a random int) gave benchmark with closer numbers where MethodStatic was max ~10% slower than direct method.通过(创建和调用返回随机整数的未来任务)的复杂实现,提供了具有更接近数字的基准,其中 MethodStatic 最多比直接方法慢 10%。 So you might be seeing 3 times slower performance due to JIT optimizations因此,由于 JIT 优化,您可能会看到性能降低 3 倍

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM