169 votes

Performance de réflexion Java

La création d'un objet en utilisant la réflexion plutôt que d'appeler le constructeur de classe entraîne-t-elle des différences de performances significatives?

167voto

Yuval Adam Points 59423

Oui - complètement. À la recherche d'une classe via la réflexion est, par ordre de grandeur, de plus en plus cher.

Citant Java documentation sur la réflexion:

Parce que la réflexion implique des types qui sont dynamiquement résolu, certains de la machine virtuelle Java optimisations ne peut pas être effectuée. Par conséquent, réfléchissant opérations baisse des performances de leur non-réfléchissant homologues, et doit être évitée dans les sections de code qui sont appelés fréquemment dans les performances des applications sensibles.

Voici un test simple j'ai piraté dans 5 minutes sur ma machine, l'exécution JRE de Sun 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);
}
}

Avec ces résultats:

35 // no reflection
465 // using reflection

Gardez à l'esprit de la recherche et de l'instanciation sont fait ensemble, et, dans certains cas, la recherche peut être reconstruit à l'écart, mais c'est juste un exemple de base.

Même si vous venez de l'instancier, vous obtenez toujours une performances:

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

Encore une fois, YMMV.

86voto

Bill K Points 32115

Oui, c'est plus lent.

Mais n'oubliez pas la merde #1 de la règle--l'OPTIMISATION PRÉMATURÉE EST LA RACINE DE TOUS les maux

(Eh bien, peut-être lié à #1 SEC)

Je vous jure, si quelqu'un est venu me voir au travail et m'a demandé ce que je serais être très vigilant sur leur code pour les prochains mois.

Vous ne devez jamais d'optimiser jusqu'à ce que vous êtes sûr que vous en avez besoin, jusqu'alors, il suffit d'écrire bon, un code lisible.

Oh, et je ne veux pas écrire de code à la con. Juste à penser à la façon la plus propre, vous pouvez éventuellement le faire-pas de copier-coller, etc. (Toujours se méfier des trucs comme boucles internes et à l'aide de la collection qui correspond le mieux à votre besoin, en Ignorant ces n'est pas "unoptimized de programmation", il est "mauvais" programmation)

Elle me fait flipper quand j'entends ce genre de questions, mais puis j'oublie que tout le monde doit passer par l'apprentissage de toutes les règles elles-mêmes avant de vraiment l'obtenir. Vous l'obtiendrez après que vous avez passé un homme-mois de débogage quelque chose à quelqu'un "Optimisé".

EDIT:

Une chose intéressante qui s'est passé dans ce fil. Vérifier le n ° 1 de la réponse, c'est un exemple de la puissance de l'compilateur est d'optimiser les choses. Le test est complètement invalide en raison de la non-réfléchissant instanciation peut être complètement pris en compte.

Leçon? Ne JAMAIS optimiser jusqu'à ce que vous avez écrit un propre, soigneusement codé solution et prouvé qu'il est trop lent.

36voto

Peter Lawrey Points 229686

Vous pouvez trouver que A a = new A () est optimisé par la JVM. Si vous placez les objets dans un tableau, ils ne fonctionnent pas aussi bien. ;) Les impressions suivantes ...

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

Cela suggère que la différence est d'environ 150 ns sur ma machine.

26voto

Esko Luontola Points 53877

Si il y a vraiment besoin de quelque chose de plus rapide que de réflexion, et ce n'est pas seulement une optimisation prématurée, alors bytecode génération avec l' ASM ou un niveau plus élevé de la bibliothèque est une option. Générer du bytecode la première fois est plus lent que juste l'utilisation de la réflexion, mais une fois que le bytecode généré, il est aussi rapide que la normale de code Java et sera optimisé par le compilateur JIT.

Quelques exemples d'applications qui utilisent la génération de code:

  • Invoquer des méthodes sur des intermédiaires générés par CGLIB est légèrement plus rapide que Java est proxies dynamiques, parce que CGLIB génère du bytecode pour ses procurations, mais proxies dynamiques utiliser uniquement de la réflexion (j'ai mesuré CGLIB à environ 10x plus rapide dans les appels de méthode, mais de créer les procurations a été plus lente).

  • JSerial génère du bytecode pour la lecture/écriture les champs des objets sérialisés, au lieu de l'aide de la réflexion. Il y a quelques repères sur JSerial du site.

  • Je ne suis pas sûr à 100% (et je n'ai pas envie de lire la source de maintenant), mais je pense que Guice génère du bytecode pour faire de l'injection de dépendances. Corrigez-moi si je me trompe.

24voto

Marcus Downing Points 5250

Il y a un peu de rétention avec la réflexion, mais c'est beaucoup plus petit sur les machines virtuelles modernes qu'auparavant.

Si vous utilisez la réflexion pour créer chaque objet simple de votre programme, alors quelque chose ne va pas. L'utiliser occasionnellement, quand vous avez de bonnes raisons, ne devrait pas poser de problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X