【问题标题】:Why is reflection slow?为什么反射慢?
【发布时间】:2019-06-04 14:48:11
【问题描述】:

是不是因为我们应该加载类(例如string),创建实例,然后搜索合适的方法,打包参数,然后调用方法?所以大部分时间都花在了这些操作上,而不是对对象的显式方法调用,对吧?

【问题讨论】:

  • 在现代 jdk/jvm 实现中并没有你想象的那么慢。

标签: java performance reflection


【解决方案1】:

当您使用反射时,您每次采取的每一步都需要经过验证。例如,当您调用一个方法时,它需要检查目标是否实际上是该方法的声明者的实例,您是否获得了正确数量的参数,每个参数的类型是否正确等等。

绝对不可能使用内联或其他性能技巧。

如果您要按名称查找类型或方法,那充其量只是涉及一个简单的映射查找 - 每次执行时都会执行一次,而不是在 JIT 时执行一次。

基本上还有很多事情要做。然而,反射已经变得比以前快了很多......如果你发现它太慢了,你很可能过度使用它。

【讨论】:

  • 另一个微妙的问题是,在使用反射时,可能需要将混淆器设置为不那么激进,从而导致收益减少。 (许多混淆器制造商声称混淆提供了性能优势以及 IP 保护和减少占用空间。参见,例如,this article。)
  • 只是调用特别慢吗?其他反射用途,例如枚举属性、获取声明类型、获取 getter/setter 方法等呢?这些也很慢吗?
  • @zespri:嗯,“慢”通常是相对于其他东西——很难说枚举属性是否“慢”,因为这也不是在反射之​​外完成的——而“调用方法”或“获取字段值”反射比直接慢得多。仅反射操作是否比您的应用需要的慢是另一回事...
  • 谢谢,这很公平。
【解决方案2】:

作为 Jon Skeet 上述回答的附录(我需要更多的声誉才能发表评论。):

反射依赖于可用的 CPU 资源;如果你的应用程序运行缓慢,反射解决不了任何问题,只是让它变慢。

就像 Java 本身一样,反射不再慢 - 它更像是一个古老的谣言;)

【讨论】:

  • 反射不慢是不对的。与手动编码的 toString 相比,三个可变类的 toString() 对我来说慢了 50%。 (我使用的是 OpenJDK 8)
  • @AjeetGanga 您的问题是您使用的是 OpenJDK 8 而不是现代 JDK/JVM。正如原帖所说,“反思不再慢”。这是真的,现代 JVM 实现更擅长反射操作。
【解决方案3】:

当您调用一个方法时,您需要知道是否使用有效参数、有效对象、返回类型是什么以及要执行的字节码。当在代码中指定了确切的方法时,java 可以快速找出这些东西并继续实际执行该方法。

当你通过反思来做这件事时,你知道的会少很多。由于代码中没有指定要调用的方法,因此这些都不能预先完成,并且 VM 必须在运行时做一些更复杂和处理器密集型的事情。

多态方法调用可能介于这两个极端之间。直到运行时您才知道要调用什么方法,但至少您可以确定方法的名称、参数和返回类型。对执行什么方法了解得越多,Java 在运行时就可以避免做的事情越多。

这证明了反射较慢,但并不是它实际上“慢”。如果你需要反射或多态的方法,使用它们,并将判断什么是“慢”留到以后。

【讨论】:

    【解决方案4】:

    如果你以适当的方式使用它,它不会那么慢。 例如,我用它来扫描模型类的所有属性,它工作得很好。

    在其他情况下,例如检查目标是否具有相同的类型或签名,绝对是慢的。

    事件有时很慢,但对于开箱即用的实现很重要...:D。

    【讨论】:

      【解决方案5】:

      根据Oracle documentations

      反射比较慢因为它涉及到动态解析的类型, 无法执行某些 Java 虚拟机优化。 因此,反射操作的性能比它们的 非反射对应物,应在代码部分中避免 在性能敏感的应用程序中经常调用它们。

      【讨论】:

        猜你喜欢
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-07
        • 2010-09-26
        • 2010-09-15
        相关资源
        最近更新 更多