10
votes

Performance du nouvel opérateur versus NewInstance () en Java

J'utilisais NewInstance () dans une zone critique de performance de mon code. La signature de la méthode est la suivante:

T Créer (Class Clasz)

Je passe quelque chose.class comme argument, je reçois une instance de quelque chose , créé avec NewInstance () . .

Aujourd'hui, je suis revenu pour effacer cette performance telledo de la liste. J'ai donc couru quelques tests de nouvel opérateur versus NewInstance () . J'ai été très surpris de la pénalité de performance de NewInstance () .

J'ai écrit un peu à ce sujet, ici: http://biasedbit.com/blog / New-vs-NewInstance /

(Désolé pour la promotion de soi ... Je placerais le texte ici, mais cette question se développerait de proportions.)

Qu'est-ce que j'aimerais savoir, c'est pourquoi le drapeau -SERVER fournit-il un tel boost de performance lorsque le nombre d'objets créés augmente largement et non pour les valeurs "basses", disent, 100 ou 1000.

J'ai appris ma leçon avec toute la chose des réflexions, il s'agit simplement de curiosité des optimisations que JVM effectue en exécution, en particulier avec le drapeau -Server . En outre, si je fais quelque chose de mal dans le test, j'apprécierais vos commentaires!

Edit: J'ai ajouté une phase d'échauffement et les résultats sont maintenant plus stables. Merci pour l'entrée!


2 commentaires

Le blog post a déplacé à nouveau .


L'article Biasedbit.com/new-vs-newinstance n'existe pas!


3 Réponses :


1
votes

4 commentaires

J'ai couru avec -xx: + printgcDétails et j'ai vu seulement 1 collection - la collection complète I forcée entre les deux tests. Je me suis assuré de fournir suffisamment de mémoire à l'application afin qu'il n'aurait pas besoin de redimensionner ou de collecter (en fait, je m'empêchais également de redimensionner en utilisant les mêmes -xmx que -xms). Dans ces conditions, je pense que GC n'était pas un facteur décisif dans les résultats.


@brunodecarvalho: Oui, je vois ce que tu veux dire, et j'ai élaboré ci-dessus. Vous devrez peut-être réécrire votre référence pour obtenir des résultats significatifs.


Oui, j'avais peur de l'effet de micro-étagère ici. Je n'aijoute que la nouvelle instance à ce réseau d'objet dans l'espoir que le compilateur ne réaliserait pas que c'est une opération inutile et supprimez toute la boucle. Je vais tester cela à nouveau à l'aide du système que j'étais sur le point d'optimiser. Cependant, je trouve un peu étrange que NewInstance () devient plus rapide que neuf. En regardant à travers la source de JDK, semble qu'il y a beaucoup de frais généraux que NewInstance () passe et nouvelle ne le fait pas.


@brunodecarvalho: Je pense qu'un constructeur trivial est optimisé, tandis qu'un constructeur non trivial vient à dominer le temps pour l'un ou l'autre.



5
votes

J'ai appris ma leçon avec toute la chose des réflexions, il s'agit simplement de curiosité des optimisations que la JVM fonctionne en exécution, en particulier avec le drapeau -Server. En outre, si je fais quelque chose de mal dans le test, j'apprécierais vos commentaires!

Répondre d'abord à la deuxième partie, votre code semble faire l'erreur classique pour les micro-repères Java et ne pas "réchauffer" la JVM avant de faire vos mesures. Votre application doit exécuter la méthode qui effectue le test à quelques reprises, ignorant les premières itérations ... au moins jusqu'à ce que les chiffres se stabilisent. La raison en est qu'un JVM doit faire beaucoup de travail pour obtenir une demande démarrée; par exemple. Chargement de cours et (quand ils sont courus quelques fois) JIT Compilation des méthodes où le temps d'application significatif est en cours de dépensement.

Je pense que la raison pour laquelle "-Server" fait une différence est que (entre autres), il modifie les règles qui déterminent quand le JIT compile. L'hypothèse est que pour un "serveur", il est préférable de jit plus tôt cela donne une start-up plus lente mais un meilleur débit. (En revanche, un "client" est syntonisé pour différer JIT Compiler afin que l'utilisateur obtienne une interface graphique de travail plus tôt.)


3 commentaires

J'ai ajouté quelques itérations d'échauffement avant d'avoir couru les tests réels et je vais de mieux, des chiffres plus stables. Avec -Server Drapeau, NewInstance () se stabilise à 2,5 ~ 2,9 fois plus lentement que neuf (à la fois pour des objets 100 et 1 kmk). Sans le maintien, il est toujours aussi élevé que 8 ~ 9 fois plus lentement pendant 100 objets jusqu'à 25 lents pendant 1 kk). Très bon conseil! :)


Un meilleur moyen de réchauffer correctement le JVM, est de le transmettre les arguments de la ligne de commande -XX: + de la commande d'impression qui fera imprimer la compilation et des optimisations de JVM. Assurez-vous ensuite qu'aucune des étapes de compilation ne se produit pendant votre course chronométrée.


@Lordoftheppigs - je suis en désaccord. En général, le meilleur moyen est de faire fonctionner un grand nombre d'itérations (alternatives), enregistrer les temps et jeter les premiers anormaux. Puis moyenne. Cela s'occupe d'autres sources de problèmes et de jitage. Le -xx: + ImprimerCompilation Approche seulement adresses JIT Anomalies.