代码之家  ›  专栏  ›  技术社区  ›  Nicholas

有没有进一步优化Java反射方法调用的方法?

  •  18
  • Nicholas  · 技术社区  · 17 年前

    public static Object invoke(Object targetObject, String methodName, Object[] arguments, Class<?>[] signature)
    

    基本操作是

    return method.invoke(targetObject, arguments);
    

    作为性能优化,我使用目标对象的类、方法名和签名(其代码可能需要一些改进)的散列来缓存该方法,但除此之外,我还能做什么?我听过一些关于早期实现的参考 这听起来很有希望,但我只是假设它们可能还不适用,我不考虑自己的字节码操作,因为我希望保持实用程序简单(但快速)。

    5 回复  |  直到 17 年前
        1
  •  60
  •   C. K. Young    17 年前

    下面的评论与Sun的实现有关,特别是OpenJDK 6。您的里程可能因其他Java平台实现而异。

    java.lang.Class 它本身会进行一些缓存,因此实现自己的缓存可能不会有太大的改进。使用和不使用手动缓存进行定时测试。

    实际的调用机制也得到了优化。反射方法的前15次运行(默认情况下)使用JNI调用;在这之后,字节码被生成,调用反射的方法的执行方式与在Java代码中直接调用该方法的执行方式相同。

        2
  •  8
  •   Nicholas    17 年前

    我围绕Chris Jester Young的答案进行了一些测试,并使用 冗长的 选项,我确实观察到编译器在第15次调用前后采取了一些操作。如果没有更复杂的测试,很难说是否有很大的性能差异,但它是有说服力的。以下是输出:

    Test# 0
    Test# 1
    Test# 2
    Test# 3
    Test# 4
    Test# 5
    Test# 6
    Test# 7
    Test# 8
    Test# 9
    Test# 10
    Test# 11
    Test# 12
    Test# 13
    Test# 14
    [Loaded sun.reflect.ClassFileConstants from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.AccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.MethodAccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.ByteVectorFactory from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.ByteVector from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.ByteVectorImpl from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.ClassFileAssembler from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.UTF8 from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded java.lang.Void from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.Label from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.Label$PatchInfo from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded java.util.AbstractList$Itr from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.MethodAccessorGenerator$1 from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.ClassDefiner from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.ClassDefiner$1 from C:\jdk1.5.0_06\jre\lib\rt.jar]
    [Loaded sun.reflect.GeneratedMethodAccessor1 from __JVM_DefineClass__]
    Test# 15
    Test# 16
    Test# 17
    

    我想 调用动力学

        3
  •  1
  •   L. Cornelius Dol    17 年前

    您肯定希望只反射一次方法对象(可能作为私有静态),并将其用于调用,而不是每次都反射出来。除非在编译时不知道缓存映射的名称,否则不要使用缓存映射。

    如果它在你的上下文中是合理的,那么你

    如果总是使用相同的parm调用(不太可能),则可以挂起parm并(包含其值的参数数组)重用它们。

    基于其他答案已经给出的理由,我不会再尝试其他任何事情。

        4
  •  0
  •   Bill K    17 年前

    另外,无论是现在还是将来,Java都很有可能优化字节码,以便在循环中使用时,调用不会比方法调用花费更多。您的“优化”实际上可能会妨碍编译器执行类似操作。(我知道我在含糊其辞,但这已经发生了——很多次)。

        5
  •  0
  •   Mike Dunlavey    17 年前

    如果调用的成本低于方法成本的10%,那么就不值得担心了。