Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Reflection: Why is it so slow?

I've always avoided Java reflection soley based on its reputation for slowness. I reached a point in the design of my current project where being able to use it would make my code much more readable and elegant, so I decided to give it a go.

I was simply astonished by the difference, I noticed at times almost 100x longer run times. Even in this simple example where it just instantiates an empty class, it's unbelievable.

class B {  }  public class Test {      public static long timeDiff(long old) {         return System.currentTimeMillis() - old;     }      public static void main(String args[]) throws Exception {          long numTrials = (long) Math.pow(10, 7);          long millis;          millis = System.currentTimeMillis();          for (int i=0; i<numTrials; i++) {             new B();         }         System.out.println("Normal instaniation took: "                  + timeDiff(millis) + "ms");          millis = System.currentTimeMillis();          Class<B> c = B.class;          for (int i=0; i<numTrials; i++) {             c.newInstance();         }          System.out.println("Reflecting instantiation took:"                + timeDiff(millis) + "ms");      } } 

So really, my questions are

  • Why is it this slow? Is there something I'm doing wrong? (even the example above demonstrates the difference). I have a hard time believing that it can really be 100x slower than normal instantiation.

  • Is there something else that can be better used for treating code as Data (bear in mind I'm stuck with Java for now)

like image 642
Mike Avatar asked Sep 08 '09 06:09

Mike


People also ask

Why is reflection so slow?

Reflection is slower Because it involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed.

Is Reflection API slow?

Reflection is not THAT slow. Invoking a method by reflection is about 3 times slower than the normal way. That is no problem if you do this just once or in non-critical situations. If you use it 10'000 times in a time-critical method, I would consider to change the implementation.

How fast is reflection Java?

Adding setAccessible(true) call makes these reflection calls faster, but even then it takes 5.5 nanoseconds per call. Reflection is 104% slower than direct access (so about twice as slow). It also takes longer to warm up.

Why is reflection not good in Java?

It's very bad because it ties your UI to your method names, which should be completely unrelated. Making an seemingly innocent change later on can have unexpected disastrous consequences. Using reflection is not a bad practice.


2 Answers

Your test may be flawed. Generally though the JVM may optimize the normal instantiation but could not make optimizations for the reflective use case.

For those wondering what the times were, I added a warmup phase and used an array to maintain the created objects (more similar to what a real program might do). I ran the test code on my OSX, jdk7 system and got this:

Reflecting instantiation took:5180ms
Normal instaniation took: 2001ms

Modified test:

public class Test {      static class B {      }      public static long timeDiff(long old) {         return System.nanoTime() - old;     }      public static void main(String args[]) throws Exception {          int numTrials = 10000000;         B[] bees = new B[numTrials];         Class<B> c = B.class;         for (int i = 0; i < numTrials; i++) {             bees[i] = c.newInstance();         }         for (int i = 0; i < numTrials; i++) {             bees[i] = new B();         }          long nanos;          nanos = System.nanoTime();         for (int i = 0; i < numTrials; i++) {             bees[i] = c.newInstance();         }         System.out.println("Reflecting instantiation took:" + TimeUnit.NANOSECONDS.toMillis(timeDiff(nanos)) + "ms");          nanos = System.nanoTime();         for (int i = 0; i < numTrials; i++) {             bees[i] = new B();         }         System.out.println("Normal instaniation took: " + TimeUnit.NANOSECONDS.toMillis(timeDiff(nanos)) + "ms");     }   } 
like image 30
Tim Bender Avatar answered Oct 05 '22 23:10

Tim Bender


Reflection is slow for a few obvious reasons:

  1. The compiler can do no optimization whatsoever as it can have no real idea about what you are doing. This probably goes for the JIT as well
  2. Everything being invoked/created has to be discovered (i.e. classes looked up by name, methods looked at for matches etc)
  3. Arguments need to be dressed up via boxing/unboxing, packing into arrays, Exceptions wrapped in InvocationTargetExceptions and re-thrown etc.
  4. All the processing that Jon Skeet mentions here.

Just because something is 100x slower does not mean it is too slow for you assuming that reflection is the "right way" for you to design your program. For example, I imagine that IDEs make heavy use of reflection and my IDE is mostly OK from a performance perspective.

After all, the overhead of reflection is likely to pale into insignificance when compared with, say, parsing XML or accessing a database!

Another point to remember is that micro-benchmarks are a notoriously flawed mechanism for determining how fast something is in practice. As well as Tim Bender's remarks, the JVM takes time to "warm up", the JIT can re-optimize code hotspots on-the-fly etc.

like image 189
oxbow_lakes Avatar answered Oct 06 '22 00:10

oxbow_lakes