java 反射真的慢吗?

大家似乎有个默认的常识:java的反射性能不好,应该使用asm、cglib之类的库替代。

看java的反射实现会有两种情况,参考NativeMethodAccessorImpl

1.调用native方法,涉及到方法查找,

2.生成字节码,动态加载类,使用MethodAccessorGenerator

就是说在调用次数超过阈值15之后,就会动态生成类,来执行反射方法,本质上和直接调用时一样的。动态生成类的模式和cglib也是一样的。

跑了几个测试看看,计算的平均每次用时,用的mac jdk8,jvm参数:-server -Xmx4g -Xms4g -Xmn512m  -Xss256k -verbose:gc (原来想贴一下代码的,的“引用”实在太难用了) 

循环次数    1000    10*1000   100*1000     1000*1000

cglib      1392ns    984ns      228ns              78ns

反射        4753ns  980ns        163ns              36ns


从测试结果看出来,次数越多,反射的性能越好,这是为什么呢?和jit编译有关,使用-XX:+PrintCompilation可以看到,循环次数到达1000*1000的时候,不仅编译层数达到了4,而且发生了OSR编译(栈上替换),运行在OSR代码中的次数越多,性能越好。

同样的cglib的FastClass也会发生jit编译,也会使用OSR编译,但是性能比不过反射,同时通过监控内存,发现cglib使用的内存也比较多,主要是动态生成类的代码不一样。

cglib的FastClass是针对一个类动态生成一个新的类;反射是针对每一个方法生成一个新的类,方法体比较小,更适合jit做动态编译、内联。

加上-XX:+PrintInlining 参数,看内联的情况,反射的方法都经过了内联优化,而使用cglib生成的代码无法内联,容易出现hot method too big的情况。

查看cglib代码可以通过System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"./");将动态生成的代码保存到文件。

你可能感兴趣的:(java 反射真的慢吗?)