Je sais qu'il y a beaucoup de sujets à parler de performances de réflexion.
Même officiel Java Docs dit que la réflexion est plus lente, mais j'ai ce code: p> } P> Je ne pense pas être une référence valide, mais au moins montrer une certaine différence.
J'ai exécuté l'attente d'attendre de voir les appels normaux de réflexion étant un peu plus lents que les réguliers. P> mais cela imprime ceci: p> juste à note, d'abord Je l'ai exécuté sans ce groupe de sysouts, puis j'ai réalisé que certaines optimisation JVM ne font que la rendre plus rapide, alors j'ai ajouté ces imprimés pour voir si la réflexion était encore plus rapide. P> Le résultat sans système est: P> 100000 regular method calls:70 milliseconds.
100000 reflective method calls without lookup:120 milliseconds.
100000 reflective method calls with lookup:129 milliseconds.
8 Réponses :
Ne jamais tester les performances Différents bits de code dans la même "course". Le JVM dispose de diverses optimisations qui le veulent que le résultat final est identique, comment les internes sont effectués peut différer. En termes plus concrètes, lors de votre test, le JVM peut avoir remarqué que vous appelez beaucoup d'objet.Tostring beaucoup et ont commencé à aligner les appels de méthode vers Object.Tostring. Il a peut-être commencé à effectuer une boucle se dérouler. Ou il aurait pu être une collection d'ordures dans la première boucle mais pas la deuxième ou la troisième boucle. P>
Pour obtenir une image plus significative, mais toujours pas une image totalement précise, vous devez séparer votre test en trois programmes distincts. P>
Les résultats sur mon ordinateur (sans impression et 1 000 000 exécutions chacun) p>
Les trois boucles fonctionnent dans le même programme P>
1000000 Méthode régulière Appels: 490 millisecondes. p>
1000000 Méthode de réflexion Appels sans recherche: 393 millisecondes. P>
Méthode de réflexion de 1000000 Appels de réflexion avec Loopup: 978 millisecondes. P> blockQuote>
Les boucles fonctionnent dans des programmes distincts p>
1000000 Méthode régulière Appels: 475 millisecondes. P>
1000000 Méthode de réflexion Appels sans recherche: 555 millisecondes. P>
Méthode de réflexion de 1000000 Appels de réflexion avec Loopup: 1160 millisecondes. P> blockQuote>
Il y a un Article de Brian Goetz sur Microbenchmarks cela vaut la peine de lire. On dirait que tu ne fais rien pour réchauffer la JVM (ce qui signifie que cela donne une chance de faire tout ce qui l'a incroyable ou d'autres optimisations qu'il va faire) avant de faire vos mesures, il est donc probable que le test non réfléchissant ne soit toujours pas réchauffé encore, et cela pourrait incliner vos chiffres. P>
Les micro-repères telles que ceci ne seront jamais exactes du tout - car la machine virtuelle "réchauffe" il s'agira de bits de code et d'optimiser les morceaux de code tel qu'il va, donc la même chose exécutée 2 minutes dans un programme pourrait beaucoup surperformer le bien au début. P>
En termes de ce qui se passe ici, je suppose que le premier bloc d'appel de méthode "normal" se réchauffe, de sorte que les blocs réfléchissants (et bien tous les appels ultérieurs) seraient plus rapides. La seule surcharge a été ajoutée en appelant de manière réfléchi une méthode que je peux constater consiste à rechercher le pointeur sur cette méthode, qui est une opération à l'échelle nanoseconde de toute façon et serait facilement mis en cache par la JVM. Le reste serait sur la manière dont la machine virtuelle est réchauffée, ce qui est au moment où vous atteignez les appels réfléchissants. P>
Hmm .. J'ai fait ce test séparé, et c'est vraiment différent.
J'ai écrit mon propre micro-repère, sans boucles, et avec J'ai exécuté cela dans Eclipse sur Ma machine une douzaine de fois, et les résultats varient un peu, mais voici ce que je reçois généralement: p> Maintenant, n'oubliez pas les mises en garde sur les microbenches décrites dans la réponse de Nathan - il y a certainement beaucoup de défauts dans ce micro de référence - et faites confiance à la documentation s'ils disent que la réflexion est beaucoup plus lente que l'invocation directe. p> p> system.nanotime () code>:
Votre implémentation pose un certain nombre de problèmes. Premièrement, Nanotime dans tous les VMS que je sais n'est que précis avec un microseconde. Deuxièmement, une grande partie du temps dans chaque référence sera consacrée à la recherche du temps, pas la méthode réelle que vous souhaitez tester - une raison pour laquelle les boucles sont effectuées dans la répétition. Troisièmement, avec une seule invocation, vous testez le temps nécessaire pour exécuter le code d'octet en mode interprété par opposition au mode compilé (rendu plus lentement qu'il n'était autrement si cette méthode était critique).
Lorsque vous avez plusieurs boucles de course longues, la première boucle peut déclencher la méthode pour compiler, ce qui entraîne les boucles ultérieures étant optimisées dès le début. Cependant, l'optimisation peut être sous-optimale car elle n'a aucune information d'exécution pour ces boucles. Le Tostring est relativement coûteux et le couple prend plus de temps que les appels de réflexions.
Vous n'avez pas besoin de programmes distincts pour éviter une optimisation de la boucle en raison d'une boucle antérieure. Vous pouvez les exécuter dans différentes méthodes. P>
Les résultats que je reçois sont p> p>
Il n'y a pas de raison inhérente à la raison pour laquelle l'appel réfléchissant devrait être plus lent qu'un appel normal. JVM peut les optimiser dans la même chose. P>
Pratiquement, les ressources humaines sont limitées et elles devaient d'abord optimiser les appels normaux. Au fil du temps, ils peuvent travailler sur optimiser les appels réfléchissants; surtout quand la réflexion devient de plus en plus populaire. P>
Cela me frappe que vous avez placé un "system.out.println (s)" appelle à l'intérieur de votre boucle de référence interne. Puisque Effectuer IO est obligé d'être lent, il "avale" votre référence et la surcharge de l'invoke devient négligeable.
Essayez de supprimer le code "println ()" Appeler et exécuter le code comme celui-ci, je suis sûr que vous " D Soyez surpris par le résultat (certains des calculs idius sont nécessaires pour éviter le compilateur optimisant les appels complètement): p> - TR P> P> P> >
Même si vous recherchez la méthode dans les deux cas (c'est-à-dire avant la 2e et 3ème boucle), La première recherche prend la place moins de temps que la seconde recherche, qui aurait dû être l'inverse et moins qu'une méthode régulière d'appel sur ma machine.
Néanmoins, si vous utilisez la 2e boucle avec la recherche de méthode et sans System.out.println code> Déclaration, je reçois ceci: p>
system.out.println code> déclaration, je reçois: p>
Je ne pense pas que l'affiche originale envisageait de réinvoyer la réflexion dans une boucle. Les applications à base de réflexion font souvent la réflexion une fois (elle ne change pas), puis utilisez les instances en cache pour effectuer l'invocation.
Oui, Steve, je viens de remarquer ça. J'étais au milieu de l'édition du post lorsque vous avez posté votre réponse et je ne suis pas sûr que mon poste édité a été perdu quelque part.
Passer par des postes ici, je ne suis pas sûr que si une opinion concluante a été faite, mais à mon avis, sur la base de la performance sur ma machine avec des boucles INT = 100 000 000; (Et pas de système.out.println ()) Call régulier: 12 800 ms, recherchez (1ère heure, 2e boucle): 12 200 ms et rechercher (2e fois, 3e boucle): 61, 600 ms et donc pour les méthodes à faible coût La réflexion n'aurait probablement aucun coût de performance à supporter.
Avez-vous le même résultat quel que soit les tests exécutés en premier? Ou mieux, séparé en 3 points?