Saltar al contenido

Rendimiento de reflexión de Java

Nora, parte de nuestro staff, nos ha hecho el favor de escribir este enunciado ya que controla muy bien dicho tema.

Solución:

Si, absolutamente. Buscar una clase a través de la reflexión es, por magnitudmás caro.

Citando la documentación de Java sobre la reflexión:

Debido a que la reflexión involucra tipos que se resuelven dinámicamente, no se pueden realizar ciertas optimizaciones de máquinas virtuales Java. En consecuencia, las operaciones reflectantes tienen un rendimiento más lento que sus contrapartes no reflectantes y deben evitarse en secciones de código que se llaman con frecuencia en aplicaciones sensibles al rendimiento.

Aquí hay una prueba simple que pirateé en 5 minutos en mi máquina, ejecutando 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);
    

Con estos resultados:

35 // no reflection
465 // using reflection

Tenga en cuenta que la búsqueda y la creación de instancias se realizan juntas y, en algunos casos, la búsqueda se puede refactorizar, pero este es solo un ejemplo básico.

Incluso si solo crea una instancia, aún obtiene un impacto en el rendimiento:

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

De nuevo, YMMV.

Sí, es más lento.

Pero recuerda la maldita regla número 1: LA OPTIMIZACIÓN PREMATURA ES LA RAÍZ DE TODO MAL

(Bueno, puede estar empatado con el #1 para SECO)

Lo juro, si alguien se me acerca en el trabajo y me pregunta esto, estaría muy atento a su código durante los próximos meses.

Nunca debe optimizar hasta que esté seguro de que lo necesita, hasta entonces, solo escriba un código bueno y legible.

Ah, y tampoco me refiero a escribir código estúpido. Solo piense en la forma más limpia en que posiblemente pueda hacerlo: sin copiar y pegar, etc. (Sin embargo, tenga cuidado con cosas como bucles internos y use la colección que mejor se adapte a sus necesidades: ignorar esto no es una programación "no optimizada" , es "mala" programación)

Me asusta cuando escucho preguntas como esta, pero luego me olvido de que todos tienen que aprender todas las reglas por sí mismos antes de que realmente lo entiendan. Lo obtendrá después de haber pasado un mes-hombre depurando algo que alguien "optimizó".

EDITAR:

Algo interesante sucedió en este hilo. Verifique la respuesta n. ° 1, es un ejemplo de cuán poderoso es el compilador para optimizar las cosas. La prueba es completamente inválida porque la instanciación no reflexiva puede eliminarse por completo.

¿Lección? NUNCA optimice hasta que haya escrito una solución limpia y bien codificada y haya demostrado que es demasiado lenta.

Puede encontrar que A a = new A() está siendo optimizado por la JVM. Si pones los objetos en un array, no funcionan tan bien. 😉 Las siguientes impresiones...

new A(), 141 ns
A.class.newInstance(), 266 ns
new A(), 103 ns
A.class.newInstance(), 261 ns

public class Run 
    private static final int RUNS = 3000000;

    public static class A 
    

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

    public static void doRegular() throws Exception 
        A[] as = new A[RUNS];
        long start = System.nanoTime();
        for (int i = 0; i < RUNS; i++) 
            as[i] = new A();
        
        System.out.printf("new A(), %,d ns%n", (System.nanoTime() - start)/RUNS);
    

    public static void doReflection() throws Exception 
        A[] as = new A[RUNS];
        long start = System.nanoTime();
        for (int i = 0; i < RUNS; i++) 
            as[i] = A.class.newInstance();
        
        System.out.printf("A.class.newInstance(), %,d ns%n", (System.nanoTime() - start)/RUNS);
    

Esto sugiere que la diferencia es de aproximadamente 150 ns en mi máquina.

Recuerda que puedes mostrar este post si lograste el éxito.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *