Java Reflection Performance

前端 未结 14 1602
感动是毒
感动是毒 2020-11-22 08:25

Does creating an object using reflection rather than calling the class constructor result in any significant performance differences?

相关标签:
14条回答
  • 2020-11-22 09:03

    Often you can use Apache commons BeanUtils or PropertyUtils which introspection (basically they cache the meta data about the classes so they don't always need to use reflection).

    0 讨论(0)
  • 2020-11-22 09:10

    If there really is need for something faster than reflection, and it's not just a premature optimization, then bytecode generation with ASM or a higher level library is an option. Generating the bytecode the first time is slower than just using reflection, but once the bytecode has been generated, it is as fast as normal Java code and will be optimized by the JIT compiler.

    Some examples of applications which use code generation:

    • Invoking methods on proxies generated by CGLIB is slightly faster than Java's dynamic proxies, because CGLIB generates bytecode for its proxies, but dynamic proxies use only reflection (I measured CGLIB to be about 10x faster in method calls, but creating the proxies was slower).

    • JSerial generates bytecode for reading/writing the fields of serialized objects, instead of using reflection. There are some benchmarks on JSerial's site.

    • I'm not 100% sure (and I don't feel like reading the source now), but I think Guice generates bytecode to do dependency injection. Correct me if I'm wrong.

    0 讨论(0)
  • 2020-11-22 09:10

    Yes there is a performance hit when using Reflection but a possible workaround for optimization is caching the method:

      Method md = null;     // Call while looking up the method at each iteration.
          millis = System.currentTimeMillis( );
          for (idx = 0; idx < CALL_AMOUNT; idx++) {
            md = ri.getClass( ).getMethod("getValue", null);
            md.invoke(ri, null);
          }
    
          System.out.println("Calling method " + CALL_AMOUNT+ " times reflexively with lookup took " + (System.currentTimeMillis( ) - millis) + " millis");
    
    
    
          // Call using a cache of the method.
    
          md = ri.getClass( ).getMethod("getValue", null);
          millis = System.currentTimeMillis( );
          for (idx = 0; idx < CALL_AMOUNT; idx++) {
            md.invoke(ri, null);
          }
          System.out.println("Calling method " + CALL_AMOUNT + " times reflexively with cache took " + (System.currentTimeMillis( ) - millis) + " millis");
    

    will result in:

    [java] Calling method 1000000 times reflexively with lookup took 5618 millis

    [java] Calling method 1000000 times reflexively with cache took 270 millis

    0 讨论(0)
  • 2020-11-22 09:11

    You may find that A a = new A() is being optimised out by the JVM. If you put the objects into an array, they don't perform so well. ;) The following prints...

    new A(), 141 ns
    A.class.newInstance(), 266 ns
    new A(), 103 ns
    A.class.newInstance(), 261 ns
    
    public class Run {
        private static final int RUNS = 3000000;
    
        public static class A {
        }
    
        public static void main(String[] args) throws Exception {
            doRegular();
            doReflection();
            doRegular();
            doReflection();
        }
    
        public static void doRegular() throws Exception {
            A[] as = new A[RUNS];
            long start = System.nanoTime();
            for (int i = 0; i < RUNS; i++) {
                as[i] = new A();
            }
            System.out.printf("new A(), %,d ns%n", (System.nanoTime() - start)/RUNS);
        }
    
        public static void doReflection() throws Exception {
            A[] as = new A[RUNS];
            long start = System.nanoTime();
            for (int i = 0; i < RUNS; i++) {
                as[i] = A.class.newInstance();
            }
            System.out.printf("A.class.newInstance(), %,d ns%n", (System.nanoTime() - start)/RUNS);
        }
    }
    

    This suggest the difference is about 150 ns on my machine.

    0 讨论(0)
  • 2020-11-22 09:12

    In the doReflection() is the overhead because of Class.forName("misc.A") (that would require a class lookup, potentially scanning the class path on the filsystem), rather than the newInstance() called on the class. I am wondering what the stats would look like if the Class.forName("misc.A") is done only once outside the for-loop, it doesn't really have to be done for every invocation of the loop.

    0 讨论(0)
  • 2020-11-22 09:15

    Yes, always will be slower create an object by reflection because the JVM cannot optimize the code on compilation time. See the Sun/Java Reflection tutorials for more details.

    See this simple test:

    public class TestSpeed {
        public static void main(String[] args) {
            long startTime = System.nanoTime();
            Object instance = new TestSpeed();
            long endTime = System.nanoTime();
            System.out.println(endTime - startTime + "ns");
    
            startTime = System.nanoTime();
            try {
                Object reflectionInstance = Class.forName("TestSpeed").newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            endTime = System.nanoTime();
            System.out.println(endTime - startTime + "ns");
        }
    }
    
    0 讨论(0)
提交回复
热议问题