Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interpreting Java reflection performance: Why is it surprisingly very fast?

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);
    }
like image 413
jbu Avatar asked Jul 13 '09 22:07

jbu


Video Answer


2 Answers

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.

like image 97
Tom Hawtin - tackline Avatar answered Sep 19 '22 08:09

Tom Hawtin - tackline


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.

like image 23
hacken Avatar answered Sep 23 '22 08:09

hacken