反射工具包ReflectASM使用

2018-03-27 09:13:17
1230次阅读
0个评论

待反射的类 SomeClass.java


public class SomeClass {
    private String name;
 
    public void foo(String name) {
        this.name = name;
    }
}

测试类 ReflectasmClient.java


import java.lang.reflect.Method;
import com.esotericsoftware.reflectasm.MethodAccess;
 
public class ReflectasmClient {
 
    public static void main(String[] args) throws Exception {
        testJdkReflect();
//        testReflectAsm();
    }
    
    public static void testJdkReflect() throws Exception {
        SomeClass someObject = new SomeClass();        
        for (int i = 0; i < 5; i++) {
            long begin = System.currentTimeMillis();
            for (int j = 0; j < 100000000; j++) {
                Method method = SomeClass.class.getMethod("foo", String.class);
                method.invoke(someObject, "Unmi");
            }
            System.out.print(System.currentTimeMillis() - begin +" ");
        }
    }
 
    public static void testReflectAsm() {
        SomeClass someObject = new SomeClass();
        for (int i = 0; i < 5; i++) {
            long begin = System.currentTimeMillis();
            for (int j = 0; j < 100000000; j++) {
                MethodAccess access = MethodAccess.get(SomeClass.class);
                access.invoke(someObject, "foo", "Unmi");
            }
            System.out.print(System.currentTimeMillis() - begin + " ");
        }
    }
}

分别运行 testJdkReflect() 和 testReflectAsm 得出各自的运行时间数据,如下:

运行 testJdkReflect():  31473 31663 31578 31658 31552

运行 testReflectAsm(): 312814 310666 312867 311234 311792

这个数据是非常恐怖的,似乎在带领我们往相反的方向上走,用 ReflectASM 怎么反而耗时多的多,高一个数量级,为什么呢?原因是大部分的时间都耗费在了

MethodAccess access = MethodAccess.get(SomeClass.class);

上,正是生成字节码的环节上,也让你体验到 MethodAccess 是个无比耗时的操作,如果把这行放到循环之外会是什么样的结果呢,同时也把方法 testJdkReflect() 中的

Method method = SomeClass.class.getMethod("foo", String.class);

也提出去,改变后的 testJdkReflect() 和 testReflectAsm() 分别如下:


public static void testJdkReflect() throws Exception {
        SomeClass someObject = new SomeClass();        
        Method method = SomeClass.class.getMethod("foo", String.class);
        for (int i = 0; i < 5; i++) {
            long begin = System.currentTimeMillis();
            for (int j = 0; j < 100000000; j++) {
                method.invoke(someObject, "Unmi");
            }
            System.out.print(System.currentTimeMillis() - begin +" ");
        }
    }
 
    public static void testReflectAsm() {
        SomeClass someObject = new SomeClass();
        MethodAccess access = MethodAccess.get(SomeClass.class);
        for (int i = 0; i < 5; i++) {
            long begin = System.currentTimeMillis();
            for (int j = 0; j < 100000000; j++) {        
                access.invoke(someObject, "foo", "Unmi");
            }
            System.out.print(System.currentTimeMillis() - begin + " ");
        }
    }


再次分别跑下 testJdkReflect() 和  testReflectAsm(),新的结果如下:

运行 testJdkReflect():  1682 1696 1858 1774 1780       ------ 平均  1758

运行 testReflectAsm(): 327 549 520 509 514                ------ 平均 483.8

胜负十分明显,上面的实验两相一比较,用 ReflectAsm 进行方法调用节省时间是 72.48%

也因此可以得到使用 ReflectASM 时需特别注意的是,获得类似 MethodAccess 实例只做一次,或它的实例应缓存起来,才是真正用好 ReflectASM。

收藏00

登录 后评论。没有帐号? 注册 一个。