Java Reflection Performance

Java Reflection Performance

Yes - absolutely. Looking up a class via reflection is, by magnitude, more expensive.

Quoting Java's documentation on reflection:

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

Here's a simple test I hacked up in 5 minutes on my machine, running Sun JRE 6u10:

public class Main {

public static void main(String[] args) throws Exception
{
doRegular();
doReflection();
}

public static void doRegular() throws Exception
{
long start = System.currentTimeMillis();
for (int i=0; i<1000000; i++)
{
A a = new A();
a.doSomeThing();
}
System.out.println(System.currentTimeMillis() - start);
}

public static void doReflection() throws Exception
{
long start = System.currentTimeMillis();
for (int i=0; i<1000000; i++)
{
A a = (A) Class.forName("misc.A").newInstance();
a.doSomeThing();
}
System.out.println(System.currentTimeMillis() - start);
}
}

With these results:

35 // no reflection
465 // using reflection

Bear in mind the lookup and the instantiation are done together, and in some cases the lookup can be refactored away, but this is just a basic example.

Even if you just instantiate, you still get a performance hit:

30 // no reflection
47 // reflection using one lookup, only instantiating

Again, YMMV.

Java Reflection: Why is it so slow?

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");
}

}

Java Reflection Performance Issue

Never performance test different bits of code in the same "run". The JVM has various optimisations that mean it though the end result is the same, how the internals are performed may differ. In more concrete terms, during your test the JVM may have noticed you are calling Object.toString a lot and have started to inline the method calls to Object.toString. It may have started to perform loop unfolding. Or there could have been a garbage collection in the first loop but not the second or third loops.

To get a more meaningful, but still not totally accurate picture you should separate your test into three separate programs.

The results on my computer (with no printing and 1,000,000 runs each)

All three loops run in same program

1000000 regular method calls: 490 milliseconds.

1000000 reflective method calls without lookup: 393 milliseconds.

1000000 reflective method calls with loopup: 978 milliseconds.

Loops run in separate programs

1000000 regular method calls: 475 milliseconds.

1000000 reflective method calls without lookup: 555 milliseconds.

1000000 reflective method calls with loopup: 1160 milliseconds.

Performance of invoking constructor by reflection

Here are results measured by JMH for following methods:

@Benchmark
@BenchmarkMode(Mode.Throughput)
public List<Integer> test1() throws Exception {
Constructor<ArrayList> constructor = ArrayList.class.getDeclaredConstructor(int.class);
return constructor.newInstance(42);
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
public List<Integer> test2() throws Exception {
return new ArrayList(42);
}

private Constructor<ArrayList> constructor = ArrayList.class.getDeclaredConstructor(int.class);

@Benchmark
@BenchmarkMode(Mode.Throughput)
public List<Integer> test3() throws Exception {
return constructor.newInstance(42);
}

results:

$java -jar benchmarks.jar -wi 5 -bs 5 -i5 -f3
...
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each, 5 calls per op
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
...
test1:
Result: 1332644.380 ±(99.9%) 325213.907 ops/s [Average]
Statistics: (min, avg, max) = (327336.040, 1332644.380, 1532709.773), stdev = 304205.290
Confidence interval (99.9%): [1007430.473, 1657858.287]
...
test2:
Result: 2690194.908 ±(99.9%) 260758.633 ops/s [Average]
Statistics: (min, avg, max) = (2173201.836, 2690194.908, 3047133.124), stdev = 243913.787
Confidence interval (99.9%): [2429436.275, 2950953.540]
...
test3:
Result: 2555898.218 ±(99.9%) 194215.211 ops/s [Average]
Statistics: (min, avg, max) = (2046939.228, 2555898.218, 2707224.497), stdev = 181669.029
Confidence interval (99.9%): [2361683.007, 2750113.429]

# Run complete. Total time: 00:01:07

Benchmark Mode Samples Score Error Units
test1 thrpt 15 1332644.380 ± 325213.907 ops/s
test2 thrpt 15 2690194.908 ± 260758.633 ops/s
test3 thrpt 15 2555898.218 ± 194215.211 ops/s

2690194/1332644 ~ it was 2 times faster to execute the second method

But don't forget the D. Knuth's quote: Premature optimization is the root of all evil

Why is reflection slow?

Every step you take needs to be validated every time you take it when you use reflection. For example, when you invoke a method, it needs to check whether the target is actually an instance of the declarer of the method, whether you've got the right number of arguments, whether each argument is of the right type, etc.

There's absolutely no possibility of inlining or other performance tricks.

If you're finding types or methods by name, that's at best going to involve a simple map lookup - which will be performed every time you execute it, rather than once at JIT time.

Basically there's a lot more to do. However, reflection has become a lot faster than it used to be... if you're finding it much too slow, you may well be overusing it.



Related Topics



Leave a reply



Submit