Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java, reflection, performance, etc

So I know this topic has been done before, e.g. Java Reflection Performance, but my particular question is, it seems that many popular libraries are implemented via annotations and reflection (Gson, Jackson, Jaxb implementations, hibernate search, for example). Many (if not all) libraries provide good (or great) performance even though they use reflection. My question is, how do they do it? Is there some "tricks" to know or do they simply use straight reflection, and the performances worries are overblown?

EDIT: So for example, when we write: MyObject obj = new Gson().fromJson(someInputStream, MyObject.class);

I can understand how the library might internally cache the Field objects, but it seems to me that it needs to reflectively instantiate the object each time, and it needs to call the setter on each field (reflectively) based on the parsed value from the json. Or is there some way to pay (all) the cost of reflection only at startup?

I've definitely noticed that Gson/Jackson etc. have relatively large startup cost and are super fast after that. So obviously I'm wondering, if I write a library that does something vaguely similar, are there tricks I need to know about? Because it appears you can't get away from some amount of reflection, on each call.

like image 543
Kevin Avatar asked Mar 10 '11 19:03

Kevin


1 Answers

What is costly is the method lookup, but method invocation once is very similar.

So, once you found what method to invoke, you just keep a reference to it, and consecutive invocations works similarly.

Of course there are situations where you want to reduce every millisecond.

Although you should beaware of micro benchmarks you could try this just to get a rough idea:

import java.lang.reflect.*;
class ReflectionOrNot { 
    public void run() { 
        try { 
            Thread.currentThread().sleep( 0 );
        } catch( InterruptedException ie ){}
    }

    public static void main( String ... args ) throws Exception { 

        ReflectionOrNot ron = new ReflectionOrNot();
        int max = 1000000;

        long start = System.currentTimeMillis();
        for( int i = 0 ; i < max ; i++ ) { 
            ron.run();
        }
        System.out.println( "Direct access took: " + ( System.currentTimeMillis() - start ) );


        Method m = ReflectionOrNot.class.getDeclaredMethod("run");
        start = System.currentTimeMillis();
        for( int i = 0 ; i < max ; i++ ) { 
            m.invoke( ron );
        }
        System.out.println( "Reflection    Took: " + ( System.currentTimeMillis() - start ) );


        start = System.currentTimeMillis();
        for( int i = 0 ; i < max ; i++ ) { 
             m = ReflectionOrNot.class.getDeclaredMethod("run");
            m.invoke( ron );
        }
        System.out.println( "Lookup + Reflect  : " + ( System.currentTimeMillis() - start ) );


    }
}

Calling 1 million times with the different approaches gave me:

C:\Users\oreyes\java>java ReflectionOrNot
Direct access took: 422
Reflection    Took: 1156
Lookup + Reflect  : 3016

C:\Users\oreyes\java>java ReflectionOrNot
Direct access took: 422
Reflection    Took: 1125
Lookup + Reflect  : 2750

C:\Users\oreyes\java>java ReflectionOrNot
Direct access took: 485
Reflection    Took: 1203
Lookup + Reflect  : 2797
like image 72
OscarRyz Avatar answered Sep 19 '22 15:09

OscarRyz