Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 方法句柄性能_Java_Performance_Methodhandle - Fatal编程技术网

Java 方法句柄性能

Java 方法句柄性能,java,performance,methodhandle,Java,Performance,Methodhandle,我编写了一个测试java.lang.invoke.MethodHandle、java.lang.reflect.Method和方法直接调用性能的小基准测试 我读到MethodHandle.invoke()性能与直接调用几乎相同。但我的测试结果显示了另一个:MethodHandleinvoke的速度大约是反射的三倍。我有什么问题?这可能是一些JIT优化的结果吗 public class Main { public static final int COUNT = 100000000;

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

我读到
MethodHandle.invoke()
性能与直接调用几乎相同。但我的测试结果显示了另一个:
MethodHandle
invoke的速度大约是反射的三倍。我有什么问题?这可能是一些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();
    }
}
公共类主{
公共静态最终整数计数=100000000;
静态测试=新测试();
静态void testInvokeDynamic()抛出NoSuchMethodException、IllegaAccessException{
int[]ar=新的int[计数];
MethodHandles.Lookup Lookup=MethodHandles.Lookup();
MethodType mt=MethodType.MethodType(int.class);
MethodHandle=lookup.findStatic(TestInstance.class,“publicStaticMethod”,mt);
试一试{
长启动=System.currentTimeMillis();

对于(int i=0;i其他人似乎也看到了类似的结果:

这是其他人的:

我运行了第二个测试,发现他们的速度几乎相同,甚至修复了该测试以进行预热。但是,我修复了它,因此它不会每次都创建args数组。在默认计数下,结果是相同的:methodhandles稍微快一点。但我计算了10000000(默认值*10),反射速度快了很多

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


@meriton对这个问题的评论链接到他的工作,看起来很有帮助:

如果
publicStaticMethod
是一个简单的实现,比如返回一个常量,那么JIT编译器很可能会对直接调用进行排序。这在methodHandles中是不可能的

例如,正如前面提到的,它的实现不是很好。如果在计算循环中将类型转换更改为int(而不是Integer),则结果更接近直接方法调用


使用复杂的实现(创建并调用返回随机整数的未来任务)给基准测试提供了更接近的数字,其中MethodStatic比direct method最多慢10%。因此,由于JIT优化,您可能会看到性能慢了3倍。

看起来这是@AlekseyShipilev在参考另一个查询时间接回答的。 在下面的链接中

如果您通读一遍,您将看到显示类似结果的其他基准测试 根据上述调查结果,差异是:

  • MethodHandle.invoke=~195ns
  • MethodHandle.invokeExact=~10ns
  • 直接呼叫=1.266ns
所以,直拨电话仍然会更快,但MH的速度非常快。 对于大多数用例来说,这应该足够了,并且肯定比旧的反射框架快(顺便说一句,根据上面的发现,在Java8VM下反射也要快得多)


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

首先确保您知道如何编写基准,请参阅:@NathanHughes他的基准有什么问题?@Andremoniy:最明显的问题是jvm没有预热。@Andremoniy:i不知道他的问题是什么,但结果是可疑的。希望有人能对此给出一个有趣的答案,+1的问题。我最近做了一个测试。服务器和客户端虚拟机之间的选择,以及方法句柄是否来自静态最终字段都会对性能产生很大影响。