Conseils de performance Java


J'ai un programme que j'ai porté de C vers Java. Les deux applications utilisent quicksort pour commander certaines données partitionnées (coordonnées génomiques).

La version Java fonctionne rapidement, mais j'aimerais la rapprocher de la version C. J'utilise le Sun JDK v6u14.

Évidemment, je ne peux pas obtenir la parité avec l'application C, mais j'aimerais apprendre ce que je peux faire pour obtenir autant de performances que raisonnablement possible (dans les limites de l'environnement).

Quelles sortes de choses puis-je faire pour tester performances des différentes parties de l'application, utilisation de la mémoire, etc.? Que ferais-je, plus précisément?

De plus, quelles astuces puis-je implémenter (en général) pour modifier les propriétés et l'organisation de mes classes et variables, réduire l'utilisation de la mémoire et améliorer la vitesse?

EDIT : J'utilise Eclipse et préférerais évidemment des options gratuites pour tous les outils tiers. Merci!

Author: Alex Reynolds, 2009-06-02

14 answers

N'essayez pas de déjouer la jvm.

En particulier:

  • N'essayez pas d'éviter la création de l'objet pour des raisons de performance

  • Utilisez des objets immuables où applicable.

  • Utilisez la portée de vos objets correctement, afin que le GC puisse faire son emploi.

  • Utilisez des primitives où vous voulez dire primitives (par exemple, int non nullable par rapport à un entier nullable)

  • Utiliser les algorithmes et les données les structures de

  • Lors de la remise de la concurrence, utilisez java.util.simultanées paquet.

  • Exactitude sur la performance. commencez par bien faire les choses, puis mesurez, puis mesurez avec un profileur, puis optimisez.

 32
Author: Andreas Petersson, 2009-06-02 09:45:31

Évidemment, profil profil profil. Pour Eclipse, il y a TPTP. Voici un article sur le pluginTPTP pour Eclipse . Netbeans a son propreprofileur . jvisualvm est agréable en tant qu'outil autonome. (L'ensemble dev.java.net le serveur semble être en panne pour le moment, mais c'est un projet très actif.)

La première chose à faire est d'utiliser la routine de tri de bibliothèque, Collections.trier ; cela nécessitera que vos objets de données soient Comparables. Ce pourrait être assez rapide et fournira certainement une bonne base.

Conseils Généraux:

  • Évitez les verrous dont vous n'avez pas besoin (votre JVM les a peut-être déjà optimisés)
  • Utilisation StringBuilder (pas StringBuffer à cause de cette chose de verrouillage que je viens de mentionner) au lieu de concaténer String objets
  • Faites tout ce que vous pouvez final ; si possible, rendez vos classes complètement immuables
  • Si vous ne modifiez pas la valeur d'une variable dans une boucle, essayez le hisser et voir si cela fait une différence (la JVM l'a peut-être déjà fait pour vous)
  • Essayez de travailler sur un ArrayList (ou même un tableau), donc la mémoire à laquelle vous accédez est contiguë au lieu d'être potentiellement fragmentée comme elle pourrait l'être avec un LinkedList
  • Quicksort peut être parallélisé; pensez à le faire (voir quicksort parallelization )
  • Réduisez autant que possible la visibilité et la durée de vie de vos données (mais ne contorsionnez pas votre algorithme pour le faire, à moins que le profilage montre que c'est une grande victoire)
 11
Author: Hank Gay, 2009-06-02 10:37:02

Utiliser un profileur:

Utilisez la dernière version de JVM de votre fournisseur. Incidemment, la mise à jour Java 6 de Sun 14 apporte des améliorations de performance.

Mesurez votre débit GC et choisissez le meilleur garbage collector pour votre charge de travail .

 5
Author: Robert Munteanu, 2009-06-02 21:33:34

Ne pas optimiser prématurément.

Mesurer les performances, puis optimiser.

Utilisez les variables finales autant que possible. Il permettra non seulement JVM pour optimiser plus, mais aussi rendre votre code plus facile à lire et à maintenir.

Si vous rendez vos objets immuables, vous n'avez pas besoin de les cloner.

Optimiser en changeant d'abord l'algorithme, puis en changeant l'implémentation.

Parfois, vous devez recourir à des techniques à l'ancienne, comme le déroulement de boucle ou mise en cache des valeurs précalculées. Rappelez-vous d'eux, même s'ils ne sont pas beaux, ils peuvent être utiles.

 4
Author: quant_dev, 2009-06-02 11:34:31

Essayez également de modifier les arguments d'exécution de la machine virtuelle - la dernière version de la machine virtuelle inclut par exemple l'indicateur suivant qui peut améliorer les performances dans certains scénarios.

-XX:+DoEscapeAnalysis 
 3
Author: Rich, 2009-06-02 10:27:27

Jvisualvm est maintenant livré avec JDK 6 - c'est la raison pour laquelle le lien cité ci-dessus ne fonctionne pas. Tapez simplement " jvisualvm ", où est l'ID du processus que vous souhaitez suivre. Vous verrez comment le tas est utilisé, mais vous ne verrez pas ce qui le remplit.

S'il s'agit d'un processus de longue durée, vous pouvez activer l'option-server lors de l'exécution. Il y a beaucoup d'options de réglage à votre disposition; c'est juste un.

 2
Author: duffymo, 2009-06-02 09:52:24

Première mise en garde - assurez-vous d'avoir effectué le profilage ou l'analyse comparative approprié avant de vous lancer dans tout travail d'optimisation. Les résultats vous éclaireront souvent et vous éviteront presque toujours beaucoup d'efforts gaspillés pour optimiser quelque chose qui n'a pas d'importance.

En supposant que vous en avez besoin, vous pouvez obtenir des performances comparables à C en Java, mais cela demande un certain effort. Vous devez savoir où la JVM fait du "travail supplémentaire" et éviter ceux-ci.

Dans particulier:

  • Évitez la création d'objet inutile . Alors que le tas et le GC de la JVM sont extrêmement rapides et efficaces (probablement les meilleurs au monde, et presque certainement meilleurs que tout ce que vous pourriez vous rouler en C), c'est toujours l'allocation de tas et cela sera battu en évitant le tas en premier lieu (allocation de pile ou de registre)
  • Évitez les primitives en boîte . Vous voulez utiliser double et non Double.
  • Utiliser des tableaux primitifs pour tout gros morceaux de données. Les tableaux primitifs Java sont fondamentalement aussi rapides que les tableaux C/C++ (ils ont une vérification des limites supplémentaire mais qui est généralement insignifiante)
  • Évitez tout ce qui est synchronisé - Le threading Java est assez décent mais il reste des frais généraux dont vous n'avez peut-être pas besoin. Donnez à chaque thread ses propres données sur lesquelles travailler.
  • Exploiter la concurrence - La prise en charge de la concurrence de Java est très bonne. Autant utiliser tous vos cœurs! C'est un grand sujet, mais il y a beaucoup de bons livres / tutoriels disponibles.
  • Utilisez des classes de collecte spécialisées pour certains types de données si vous avez des exigences très spécifiques, par exemple en prenant en charge certains algorithmes de tri/recherche spécialisés. Vous devrez peut-être lancer les vôtres, mais il existe également de bonnes bibliothèques avec des classes de collection hautes performances disponibles qui peuvent répondre à vos besoins-voir par exemple Javoltion
  • Évitez les héritages de grande classe - c'est une odeur de design dans code de performance. Chaque couche d'abstraction vous coûte des frais généraux. Le code Java très rapide finira souvent par ressembler plutôt à C....
  • Utilisez des méthodes statiques - le JIT peut les optimiser extrêmement bien. Il les alignera généralement.
  • Utilisez les classes concrètes finales - encore une fois, le JIT peut très bien les optimiser en évitant les appels de fonction virtuels.
  • Générer votre propre bytecode - si tout le reste échoue, cela peut être une option viable si vous voulez le performances maximales absolues de la JVM. Particulièrement utile si vous avez besoin de compiler votre propre DSL. Utilisez quelque chose commeASM .
 2
Author: mikera, 2012-08-17 02:43:45

Si votre algorithme est lourd en CPU, vous pouvez envisager de tirer parti de la parallélisation. Vous pourrez peut-être trier plusieurs threads et fusionner les résultats plus tard.

Ce n'est cependant pas une décision à prendre à la légère, car écrire du code simultané est difficile.

 1
Author: Simon Nickerson, 2009-06-02 09:45:15

Ne pouvez-vous pas utiliser les fonctions de tri incluses dans la bibliothèque Java?

Vous pouvez au moins regarder la différence de vitesse entre les deux fonctions de tri.

 1
Author: Peter Stuifzand, 2009-06-02 09:50:16

Méthodiquement, vous devez profiler l'application et vous faire une idée des composants de votre programme qui nécessitent beaucoup de temps et de mémoire: regardez ensuite de plus près ces composants, afin d'améliorer leurs performances (voirLoi d'Amdahl ).

À partir d'un point de vue technologique pur, vous pouvez utiliser des compilateurs java-to-nativecode, comme jet d'Excelsior, mais je dois noter que la JVM récente est vraiment rapide, donc la machine virtuelle ne devrait pas avoir d'impact significatif.

 0
Author: akappa, 2009-06-02 09:42:10

Votre code de tri ne s'exécute-t-il qu'une seule fois, par exemple dans un utilitaire en ligne de commande qui trie simplement, ou plusieurs fois, par exemple une webapp qui trie en réponse à une entrée utilisateur?

Il y a de fortes chances que les performances augmentent considérablement après l'exécution du code plusieurs fois, car la machine virtuelle HotSpot peut optimiser de manière agressive si elle décide que votre code est un hotspot.

C'est un gros avantage par rapport au C/C++.

La machine virtuelle, lors de l'exécution, optimise le code souvent utilisé, et il le fait assez bien. Les performances peuvent en fait dépasser celles de C/C++ à cause de cela. Vraiment. ;)

Votre comparateur personnalisé pourrait cependant être un lieu d'optimisation.

Essayez d'abord de vérifier les choses peu coûteuses (par exemple la comparaison int) avant les choses plus chères (par exemple la comparaison de chaînes). Je ne sais pas si ces conseils s'appliquent parce que je ne connais pas votre comparateur.

Utilisez l'une ou l'autre des collections.tri (liste, comparateur) ou tableaux.trier (tableau, comparateur). La variante de tableau sera un bit plus rapide, voir la documentation respective.

Comme Andreas l'a dit précédemment: n'essayez pas de déjouer la machine virtuelle.

 0
Author: Huxi, 2009-06-02 11:10:23

Il existe peut-être d'autres voies d'amélioration des performances que la micro-optimisation du code. Que diriez-vous d'un algorithme différent pour réaliser ce que vous vouliez que votre programme fasse? Peut-être une structure de données différente?

Ou échangez de l'espace disque/ram contre de la vitesse, ou si vous pouvez abandonner un peu de temps à l'avance pendant le chargement de votre programme, vous pouvez précalculer des tables de recherche au lieu de faire des calculs - de cette façon, le traitement est rapide. C'est-à-dire, faire des compromis sur d'autres ressources disponible.

 0
Author: Chii, 2009-06-02 13:53:23

Voici ce que je ferais, dans n'importe quelle langue. Si des échantillons montrent que votre routine de comparaison de tri est active un grand pourcentage du temps, vous pourriez trouver un moyen de la simplifier. Mais peut-être que le temps va ailleurs. Diagnostiquer d'abord, pour voir ce qui est cassé, avant de réparer quoi que ce soit. Les chances sont, si vous corrigez la plus grande chose, alors quelque chose d'autre sera la plus grande chose, et ainsi de suite, jusqu'à ce que vous avez vraiment obtenu une assez bonne accélération.

 0
Author: Mike Dunlavey, 2017-05-23 12:13:53

Profilez et ajustez votre programme java et votre machine hôte. La plupart des codes suivent la règle 80/20. C'est 20% du code 80% du temps, alors trouvez-le 20% et rendez-le aussi vite que possible. Par exemple, l'article Tuning Java Servers ( http://www.infoq.com/articles/Tuning-Java-Servers) fournit une description de l'exploration à partir de la ligne de commande, puis isolez le problème à l'aide d'outils tels que Java Flight Recorder, Eclipse Memory Analyser et JProfiler.

 0
Author: srinath_perera, 2014-12-06 00:09:53