Any way to further optimize Java reflective method invocation?

前端 未结 5 1345
感动是毒
感动是毒 2020-12-08 08:22

I am wondering if there are any additional optimizations I can implement to improve the speed of reflective invocations in Java. Not that the performance is prohibitive, but

相关标签:
5条回答
  • 2020-12-08 08:34

    Premature Optimization is generally bad. No matter what, your performance will still be many times that of a dynamic language, so I really wouldn't worry about it beyond documenting the fact that it uses reflection and therefore might be sub-optimal.

    Also, there is a good chance that either now or in the future, Java will optimize the bytecode so that the call doesn't cost anything more than a method call when used in a loop. Your "Optimization" may actually hinder the compilers ability to do something like that. (I know I'm being vague, but this has happened--a LOT).

    0 讨论(0)
  • 2020-12-08 08:53

    I ran some tests around Chris Jester-Young's answer and using the verbose options, I definitely observed the compiler take some action around the 15th invocation. Hard to say if there's much performance differential without a more sophisticated test, but it is persuasive. Here's the output:

    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
    

    I guess the InvokeDynamic business is not attracting too many developers on the basis of reflection speedup/elimination.

    Thanks Chris.

    0 讨论(0)
  • 2020-12-08 08:54

    The comments below relate to Sun's implementation, in particular OpenJDK 6. Your mileage may vary with other Java platform implementations.

    java.lang.Class does some caching itself, so implementing your own cache may not improve things very much. Do timing tests with and without manual caching.

    The actual invocation mechanism is optimised too. The first 15 runs (by default) of your reflected method is called using JNI; after that, bytecode is generated and calling that reflected method would perform identically to calling that method directly in Java code.

    0 讨论(0)
  • 2020-12-08 08:54

    If the cost of invocation is less than 10% of the cost of what goes on in the method, it's hardly worth worrying about.

    You can determine that by running it 10^6 times in a loop, with and without the guts of the routine. Time it with a stopwatch, so seconds translate to microseconds.

    0 讨论(0)
  • 2020-12-08 08:55

    You will definitely want to reflect the method object only once (likely as a private static), and use that for the invocation rather than reflect it out every time. Don't bother with a cache map unless you don't know the name at compile time.

    If it is sensible in your context, you may want to hang on to and reuse the argument array object (don't forget to null the array elements on method exit to prevent temporary GC inhibition).

    If always invoked with the same parms (highly unlikely), you could hang onto the parms and (the argument array with it's values) reuse them.

    I would not attempt anything beyond that for the reasons already given by the other answers.

    0 讨论(0)
提交回复
热议问题