为什么Java反射慢
为什么Java反射慢?Java反射慢好像成了一个不言自明的命题,人们不经思考就会说Java反射慢而从未研究里面的原理。在互联网上搜索这个问题只发现了零星的一些答案,零碎不全面而没什么参考价值。首先需要知道的是反射执行方法的情景中,慢的并不是单纯的执行效率,而是其他地方。
首先是访问速度的问题。这里涉及到少许JVM和字节码层次的知识,静态代码中访问一个字段或者方法是直接根据字节偏移访问的,一切在编译时已经确定,而反射代码中访问则是需要在运行时通过遍历来查找,性能差别之大就类似已知下标从数组中取出对象和已知对象部分属性从数组中取出对象。这并非全部,随后还需要进行访问控制检查以确定取到的字段或方法是否可访问可执行,方法执行还要进行类型检查,而这些在静态执行中都是不存在的,这就带来了巨大的访问速度差异(其实还有一点是反射是通过JNI来执行的,JVM环境与Native环境之间跳转也需要时间)。
如果只是访问速度慢的话,是不是对于比较重的方法而言就不存在明显的性能差异了呢?这显然跟事实相违。反射还存在一些JIT优化的问题。要知道脱离JIT谈Java性能都是耍流氓,有没有JIT的Java性能差距能达到好几个数量级。关于反射的JIT优化并非像有些博客和知乎答主所说是一点也无,优化是当然存在的,比如de-reflection-optimization就是一项很好的优化,但是比起静态代码而言还是要少了非常多的重要优化,(比如方法内联。关于为什么方法内联可以显著提高性能这里就不展开了。)以至于最终还是带来了非常巨大的性能差异。
顺便提一下JDK1.7引入的MethodHandler这个东西。甲骨文设计了一个新的JVM指令(invokedynamic)来支持这个东西,这个东西第一眼看上去像是反射的替代品,但是实际上是被设计用来更好的支持动态语言的,JDK1.8上的Lambda和Nashorn就是它支持下的产物。但是不要以为这个东西速度就很快了,无数多个性能测试表明这东西速度比反射还慢,它访问资源同样要遍历,要经过几道检查。同样的,它支持下的Lambda也快不到哪里去,如果只是遍历数组这种操作还是省省不要用Lambda了,得不偿失。