I've seen other threads saying java reflection performance is 10-100x slower than when using non-reflection calls.
My tests in 1.6 have shown that this is not the case but I found some other interesting things that I need someone to explain to me.
I have objects that implement my interface. I did three things 1) using a reference to an Object I cast that object to the interface and call the method through the interface 2) using a reference to the actual object call the method directly and 3) call the method through reflection. I saw that #1 interface call was fastest followed closely by #3 reflection but I noticed that the direct method call was the slowest by a good margin.
I don't understand that, I would've expected the direct call to be fastest, then the interface, then reflection would be much much more slow.
Blah and ComplexClass are in a different package from the main class and both have a doSomething(int x) method that implements the interface and just prints the integer x.
Here are my results (times in ms, results very similar w/ multiple trials): calling a method directly: 107194 calling a method directly from an object cast to an interface: 89594 calling a method through reflection: 90453
Here is my code:
public class Main
{
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
Blah x = new Blah();
ComplexClass cc = new ComplexClass();
test((Object) x, cc);
}
public static void test(Object x, ComplexClass cc)
{
long start, end;
long time1, time2, time3 = 0;
int numToDo = 1000000;
MyInterface interfaceClass = (MyInterface) x;
//warming up the cache
for (int i = 0; i < numToDo; i++)
{
cc.doSomething(i); //calls a method directly
}
start = System.currentTimeMillis();
for (int i = 0; i < numToDo; i++)
{
cc.doSomething(i); //calls a method directly
}
end = System.currentTimeMillis();
time1 = end - start;
start = System.currentTimeMillis();
for (int i = 0; i < numToDo; i++)
{
interfaceClass.doSomething(i); //casts an object to an interface then calls the method
}
end = System.currentTimeMillis();
time2 = end - start;
try
{
Class xClass = x.getClass();
Class[] argTypes =
{
int.class
};
Method m = xClass.getMethod("doSomething", argTypes);
Object[] paramList = new Object[1];
start = System.currentTimeMillis();
for (int i = 0; i < numToDo; i++)
{
paramList[0] = i;
m.invoke(x, paramList); //calls via reflection
}
end = System.currentTimeMillis();
time3 = end - start;
} catch (Exception ex)
{
}
System.out.println("calling a method directly: " + time1);
System.out.println("calling a method directly from an object cast to an interface: " + time2);
System.out.println("calling a method through reflection: " + time3);
}
Putting all the tests into the same program is a microbenchmarking mistake - there is a certain warm up associated with Java performance. This is the most important failing.
Put your tests in separate programs. Then run the tests several times, so you get a feeling for when warm up has finished and statistical significance.
Also you have a huge method containing your inner loop. Hotspot appears to be better at dealing with this than it used to be, but it still isn't good.
You should find that with -server
calling a virtual method (even if loaded by a different class loader) in a tight loop gets completely optimised away. It therefore doesn't make much sense to say how much fast a direct call is than a reflective call.
First, reflection got much faster in the most recent JDKs. Second I expect that the Hot Spot compiler is going to optimize all of these calls to roughly the code. It can do run time analysis to realize that you are invoking the same function over and over again so it can optimize out the reflection (and virtual function call). Same thing with the interface example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With