MethodHandler 不会产生 boxing

    static int add(int a, int b){
        return a + b;
    }
    @Test
    public void directAdd() throws Throwable {
        // 编译 31ms
        System.out.println(System.currentTimeMillis());
        int r = 0;
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                r += add(i, j);
            }
        }
        System.out.println(r);
        System.out.println(System.currentTimeMillis());
    }
    @Test
    public void directAddBoxing() throws Throwable {
        // 使用 Integer,引入 boxing unboxing 开销,526ms
        System.out.println(System.currentTimeMillis());
        int r = 0;
        for (Integer i = 0; i < 10000; i++) {
            for (Integer j = 0; j < 10000; j++) {
                r += add(i, j);
            }
        }
        System.out.println(r);
        System.out.println(System.currentTimeMillis());
    }
    @Test
    public void invokeReflectionTest() throws Throwable {
        // 反射 1s127ms
        Method add = RuntimeOptimization.class.getDeclaredMethod("add", int.class, int.class);
        System.out.println(System.currentTimeMillis());
        int r = 0;
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                r += (int) add.invoke(null, i, j);
            }
        }
        System.out.println(r);
        System.out.println(System.currentTimeMillis());
    }
    @Test
    public void invokeMethodHandlerTest() throws Throwable {
        // MethodHandler 210ms
        MethodHandle add = MethodHandles.lookup().findStatic(RuntimeOptimization.class, "add", MethodType.methodType(int.class, int.class, int.class));
        System.out.println(System.currentTimeMillis());
        int r = 0;
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                r += (int) add.invokeExact(i, j);
            }
        }
        System.out.println(r);
        System.out.println(System.currentTimeMillis());
    }

可见 MethodHandler 比boxing/unboxing的编译版本还要快,显然它在编译时消除了boxing开销,也就是说 invokeExact(Object...) 并不会真的 boxing,Object invokeExtract 也不返回 Object 后再 unboxing 到 int。所以不必纠结为何不提供 add.pushInt(a).pushInt(b).invoke() 这样的结构,编译器已经做了这项优化。
当然,再怎么折腾还是比编译版本慢 10 倍,目前没有更好的办法了。

posted @ 2023-05-05 16:02  Inshua  阅读(15)  评论(0编辑  收藏  举报