J'ai toujours évité les réflexions en Java, uniquement en raison de sa réputation de lenteur. J'ai atteint un point dans la conception de mon projet actuel où être capable de l'utiliser rendrait mon code beaucoup plus lisible et élégant, alors j'ai décidé de l'essayer.
J'ai été tout simplement étonné par la différence, j'ai remarqué des temps d'exécution parfois presque 100x plus longs. Même dans cet exemple simple où il suffit d'instancier une classe vide, c'est incroyable.
class B {
}
public class Test {
public static long timeDiff(long old) {
return System.currentTimeMillis() - old;
}
public static void main(String args[]) throws Exception {
long numTrials = (long) Math.pow(10, 7);
long millis;
millis = System.currentTimeMillis();
for (int i=0; i<numTrials; i++) {
new B();
}
System.out.println("Normal instaniation took: "
+ timeDiff(millis) + "ms");
millis = System.currentTimeMillis();
Class<B> c = B.class;
for (int i=0; i<numTrials; i++) {
c.newInstance();
}
System.out.println("Reflecting instantiation took:"
+ timeDiff(millis) + "ms");
}
}
Donc en fait, mes questions sont
-
Pourquoi est-ce si lent ? Y a-t-il quelque chose que je fais mal ? (même l'exemple ci-dessus montre la différence). J'ai du mal à croire que cela puisse vraiment être 100x plus lent qu'une instanciation normale.
-
Y a-t-il quelque chose d'autre qui puisse être mieux utilisé pour traiter le code comme des données (n'oubliez pas que je suis coincé avec Java pour le moment) ?
1 votes
Il y a également un fil de discussion à stackoverflow.com/questions/435553/java-reflection-performance qui vous incite à lire la documentation de l'API de réflexion
2 votes
L'évaluation comparative de la JVM est difficile. La JVM de Hotspot ne se laissera pas berner par un test naïf comme celui-ci qui ne fait rien.
0 votes
Il faut juste noter que c'est une très mauvaise façon de faire des benchmarks, même pour un microbenchmark.
1 votes
Le benchmark ne prend pas en compte la phase de réchauffement et de compilation de la JVM. Enroulez le contenu de main dans une boucle, et vous verrez des chiffres complètement différents lors des exécutions suivantes.
1 votes
Je viens de voir la JVM optimiser la réflexion 35 fois. Exécuter le test de façon répétée dans une boucle est la façon de tester un code optimisé. Première itération : 3045ms, deuxième itération : 2941ms, troisième itération : 90ms, quatrième itération : 83ms. Code : c.newInstance(i). c est un Constructeur. Code non réfléchi : new A(i), qui donne des temps de 13, 4, 3 ms. Donc oui, la réflexion dans ce cas était lente, mais pas autant que ce que les gens concluent, parce que tous les tests que je vois, ils exécutent simplement le test une fois sans donner à la JVM l'occasion de remplacer les codes d'octets par du code machine.