一文看懂为什么java反射性能慢、效率低

简介

稍微了解Java反射的伙伴都知道,java反射是存在一定的性能损耗的,那为什么使用反射创建类会比直接调用类构造函数创建对象慢呢?

java反射之所以慢,根本原因是编译器没法对反射相关的代码做优化。

我们都知道 Java 代码是需要编译才能在虚拟机里运行的,但其实 Java 的编译期是一段不确定的操作过程。因为它可能是一个前端编译器(如 Javac)把 *.java 文件编译成 *.class 文件的过程;也可能是程序运行期的即时编译器(JIT 编译器,Just In Time Compiler)把字节码文件编译成机器码的过程;还可能是静态提前编译器(AOT 编译器,Ahead Of Time Compiler)直接把 *.java 文件编译成本地机器码的过程。

其中即时编译器(JIT)在运行期的优化过程对于程序运行来说更重要,Java虚拟机在编译阶段的代码优化就在这里进行,由于反射涉及动态解析的类型,因此无法执行某些Java虚拟机优化。因此,反射操作的性能要比非反射操作慢,因此应该避免在对性能敏感的应用程序中频繁使用Java反射来创建对象。

代码测试

结果

使用构造函数创建耗时:35
使用java反射创建耗时:465

扩展

如果确实需要比反射更快的速度,那么可以选择使用ASM或更高级别的库生成字节码。

ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。说白了asm是直接通过字节码来修改class文件。

ASM 第一次生成字节码比仅使用反射慢,但是一旦生成了字节码,它便与普通Java代码一样快,并且将由JIT编译器进行优化

我们熟知的CGLIB(Code Generation Library)的底层就是是通过 ASM 来实现的。

在CGLIB生成的代理上调用方法比Java的动态代理要快一些,因为CGLIB为其代理生成字节码,但是创建代理要慢一些。

总结

虽然java反射性能存在一定损耗,但并不是说我们就不该用java反射,到底使不使用java反射,应该根据我们的程序设计需求来决定。

如果你只是根据某些条件或配置文件来使用java反射创建对象,然后接下来就做其它操作(如数据库查询等),那其实java反射损耗的那点性能可以忽略不计。

但如果你想在连续循环中通过反射不断创建大量对象,那这是不可取的。

+3

《一文看懂为什么java反射性能慢、效率低》有3个想法

发表评论

邮箱地址不会被公开。