Optimisation des performances Java

Ce blog couvre des conseils d’optimisation des performances Java, en discutant des stratégies clés pour optimiser les performances et en offrant des conseils pratiques aux développeurs afin d’améliorer l’efficacité lors du développement.
6 min de lecture
Sandeep Pratap Singh
Sandeep Pratap Singh
Spécialiste technique
6 min de lecture
Optimisation des performances Java

La performance d'une application Java n'est qu'un simple mot à la mode jusqu'à ce que vous en subissiez réellement les conséquences. Elle peut varier en fonction de votre interprétation et de votre expérience. Dans ce blogue, je me concentre spécifiquement sur le tas Java et l’optimisation de la performance Java.

Le bloc finally est un outil clé pour prévenir les fuites de ressources

Vous pouvez être confronté à l’un des problèmes ci-dessous :

  1. Application lente –

    Votre application peut ne pas bien répondre parce qu’elle passe trop de temps à nettoyer la mémoire plutôt qu’à exécuter les processus nécessaires.

  2. Consomme trop de mémoire –

    L’utilisation de la mémoire de l’application est liée au nombre et à la taille des objets vivants qui se trouvent dans la machine virtuelle Java (JVM) à un moment donné. Cela peut être dû à la présence d’objets valides qui doivent demeurer dans la mémoire du tas Java, ou parce que le programmeur a oublié de supprimer la référence à des objets indésirables (habituellement appelés « fuites de mémoire » dans le jargon Java).

Voici quelques astuces simples d’optimisation de la performance Java que vous pouvez appliquer pendant votre processus de développement :

  1. Attribution de la mémoire JVM

    Lorsque l’empreinte mémoire atteint le seuil limite, la JVM lance l’exception java.lang.OutOfMemoryError. Cette exception se produit principalement pour les raisons suivantes :

    • L'espace JavaHeap est insuffisant pour créer de nouveaux objets. Vous pouvez augmenter la mémoire allouée à l’aide de -Xmx (java.lang.OutOfMemoryError: Java heap space).java.lang.OutOfMemoryError: Java heap space
    • La génération permanente peut être faible. On peut l’augmenter avec XX:MaxPermSize=256m(java.lang.OutOfMemoryError: PermGen space)java.lang.OutOfMemoryError: PermGen space
    • L’espace d’échange peut être épuisé à cause d’une java.lang.OutOfMemoryError

    L’interface Java Native (JNI) Heap manque de mémoire, même si JavaHeap et PermGen ont de la mémoire disponible. Cela se produit habituellement si vous faites beaucoup d’appels JNI lourds, alors que les objets de JavaHeap occupent peu d’espace. Dans ce cas, le fil du collecteur de déchets (GC) peut ne pas ressentir le besoin de nettoyer la mémoire JavaHeap tandis que la mémoire JNI Heap continue d’augmenter jusqu’à son épuisement.

    Il est recommandé d’augmenter l’espace du tas Java jusqu’à concurrence de la moitié de la RAM totale disponible sur le serveur. Un espace de tas supérieur peut entraîner des problèmes de performance. Par exemple, si votre serveur dispose de 16 Go de RAM, l’espace de tas maximal à utiliser devrait donc être de 8 Go.

    Si vous utilisez Tomcat, suivez les étapes ci-dessous :

    Ouvrez le fichier catalina.bat (TomcatInstallDirectory/bin/catalina.bat).

    Définissez JAVA_OPTS=%JAVA_OPTS% -Xms1024m -Xmx1024m

    [Où Xms est le regroupement initial (démarrage) de la mémoire et Xmx est le regroupement de mémoire maximum]

  2. Concaténation programmatique des chaînes

    Vous pouvez utiliser StringBuilder pour concaténer des chaînes de façon programmatique. Il existe de nombreuses façons différentes de concaténer des chaînes en Java. Vous pouvez, par exemple, utiliser le simple « + » ou « += », l’antique StringBuffer, ou un StringBuilder.

  3. Utilisation des types primitifs

    autant que possible. Un autre moyen rapide et facile d’éviter toute surcharge et d’améliorer la performance de votre application est d’utiliser des types primitifs plutôt que leurs classes enveloppantes. Il est donc préférable d’utiliser un « int » au lieu d’un Integer, ou un « double » au lieu d’un Double. Cela permet à votre JVM de stocker la valeur dans la pile au lieu du tas pour réduire la consommation de mémoire et la gérer de façon plus efficace.

  4. Éviter BigInteger et BigDecimal

    Puisque nous parlons déjà de types de données, examinons aussi rapidement BigInteger et BigDecimal. Ce dernier est notamment populaire pour sa précision. Mais cela a un coût. BigInteger et BigDecimal exigent beaucoup plus de mémoire qu’un simple « long » ou « double » et ralentissent considérablement tous les calculs.

  5. Vérification du niveau actuel de journalisation

    Cette recommandation devrait aller de soi, mais malheureusement, on trouve beaucoup de code qui ne la suit pas. Avant de créer un message de débogage, il faut toujours vérifier le niveau de journalisation d’abord. Sinon, vous pourriez créer une chaîne pour votre message de journal qui sera ignorée par la suite.

  6. Évitez d’utiliser « + » pour concaténer des chaînes dans une seule instruction

    Lorsque vous avez codé votre première application en Java, quelqu’un vous a probablement dit que vous ne devriez pas concaténer des chaînes avec « + ». Et c’est vrai si vous concaténez des chaînes dans votre logique applicative. Les chaînes sont immuables et le résultat de chaque concaténation est stocké dans un nouvel objet chaîne. Cela nécessite de la mémoire supplémentaire et ralentit votre application, surtout si vous concaténez plusieurs chaînes dans une boucle.

  7. Utilisation d’ArrayList au lieu de LinkedList

    L’exploration interne des nœuds ArrayList du début à la fin de la collection est beaucoup plus rapide que celle de LinkedList. En conséquence, les requêtes implémentées dans cette classe peuvent être plus rapides. L’itération avec un itérateur sur tous les éléments est plus rapide pour ArrayList que pour LinkedList. Les ArrayLists peuvent générer beaucoup moins d’objets à récupérer pour le GC comparativement aux LinkedLists.

  8. Utilisation de méthodes personnalisées de conversion entre les types de données

    Pour réduire le nombre d’objets temporaires, utilisez toujours des méthodes personnalisées de conversion, spécialement pour les chaînes et les flux.

  9. N’optimisez pas avant de savoir si c’est nécessaire

    Ceci pourrait être l’un des conseils d’optimisation les plus importants. Vous devriez suivre les bonnes pratiques et essayer d’implémenter vos cas d’utilisation de façon efficace. Mais cela ne signifie pas que vous devez remplacer toutes les bibliothèques standards ou créer des optimisations complexes avant d’avoir prouvé que c’est nécessaire.

  10. Comprendre le vrai coût des flux (streams)

    Les flux sont un excellent ajout au langage Java, permettant de migrer aisément des logiques sujettes à l’erreur avec des boucles « for » vers des logiques génériques, ce qui mène à des blocs de code plus réutilisables et cohérents. Mais cette commodité a un prix, il y a un coût de performance associé à l’emploi des flux. Heureusement, ce coût n’est généralement pas très élevé.

  11. Être conscient du coût du formatage et de l’analyse

    Soyez toujours conscient du coût de l’analyse et du formatage des objets de type date. À moins d’avoir besoin de la chaîne immédiatement, il vaut mieux la représenter par un horodatage UNIX.

  12. Utilisez Apache Commons StringUtils.replace au lieu de string.replace

    En général, la méthode string.replace fonctionne bien et est efficace, surtout avec Java. Mais si votre application nécessite de nombreuses opérations de remplacement et que vous n’avez pas la dernière version de Java, il peut être avisé de chercher des alternatives plus rapides et efficaces.

  13. Itération plutôt que récursivité

    Les langages modernes de programmation fonctionnelle comme Scala encouragent l’utilisation de la récursivité, car ils permettent d’optimiser les algorithmes de récursivité terminale en les rendant itératifs. Vous pourriez gaspiller beaucoup d’espace sur la pile pour quelque chose qui aurait pu être fait avec quelques variables locales. Donc, préférez toujours l’itération à la récursivité.

  14. Utilisation de EnumSet ou EnumMap au lieu de HashSet et HashMap

    Il existe des cas où le nombre de clés possibles dans une carte est connu d’avance – par exemple, lors de l’utilisation d’une carte de configuration. Si ce nombre est relativement faible, vous devriez réellement envisager d’utiliser EnumSet ou EnumMap au lieu de HashSet ou HashMap classiques.

  15. Évitez les appels répétés lorsque la taille de la collection est connue

    Il n’est pas nécessaire d’appeler de façon répétitive Iterator.hasNext() et Enumerator.hasMoreElements() lorsque la taille de la collection est connue. Utilisez plutôt collection.size() et un compteur de boucle.

  16. Optimisez vos méthodes hashCode() et equals()

    Une bonne méthode hashCode() est essentielle, car elle permet d’éviter de faire appel à la méthode equals(), beaucoup plus dispendieuse, en produisant plus de compartiments de hachage distincts pour chaque ensemble d’instances.

  17. Utilisez bien le bloc « finally »

    Le bloc « finally » est un outil clé pour prévenir les fuites de ressources. Lorsqu’un fichier est fermé ou qu’une ressource quelconque est libérée, placez le code dans un bloc « finally » pour assurer que la ressource est toujours récupérée. Mais « finally » est utile pour plus que la gestion d’exceptions — il permet au programmeur d’éviter que du code de nettoyage ne soit contourné accidentellement par un « return », un « continue » ou un « break ». Mettre le nettoyage dans un bloc « finally » est toujours une bonne pratique, même lorsque aucune exception n’est prévue.

  18. Utilisez un profileur pour trouver le goulet d’étranglement

    Après avoir suivi la première recommandation et identifié les parties de votre application devant être améliorées, plusieurs outils disponibles sur le marché peuvent vous aider à diagnostiquer le goulet d’étranglement de performance. Ces outils seront abordés dans la prochaine partie de cette série de blogues.

Références :

https://stackoverflow.com

https://dzone.com

Etiquettes
Partager sur
ERS Génie Blogues Optimisation des performances Java