Java Optimisation Tips

14 Juil

Lors d’une baisse de charge que nous avons vécu dans notre équipe il y a quelques jours et pour ne pas rester les mains croisées ou surfer à travers les réseaux sociaux, les blogs IT et l’actualité technologique, nous avons décidé de faire un peu de refactoring (chose que je vois nécessaire à chaque phase de développement et non pas seulement lors d’une baisse de charge).

Pour s’y faire et dans le but de mieux savoir sur les techniques niveau codage qui peuvent nous aider à améliorer les performances de notre produit, j’ai commencé à voir coté du net et je me suis tomber sur un bon article écrite par Philippe Prados un mec costo de chez IBM.

Alors sans trop parler le but de ce billet est de prendre notes de ces tips que j’ai aimé et que j’ai pu utiliser peut être que ça sera utile une autre fois :

1-Déclaré des méthodes utilitaires

Une méthode qui ne manipule pas d’attribut ni de variables statiques est un utilitaire. Vous pouvez la déclarer static. Cela améliore la vitesse d’exécution. Par exemple, la méthode copyValueOf(char) de la classe String est déclarée static car elle ne manipule pas d’instance.

2-Réutilisez les instances

Créer des objets est plus coûteux que les réutiliser. Déclarez des instances statiques et réinitialisez les

3-Elimination des sous expressions commune.

Cela consiste à déplacer les sous expressions pour ne les calculer qu’une seule fois.

 double prixTTC1 = prix1*(1+tva);
 double prixTTC2 = prix2*(1+tva);
 

devient

 double sousexpr = 1+tva;
 double prixTTC1 = prix1*sousexpr;
 double prixTTC2 = prix2*sousexpr;
 

Les compilateurs savent parfois identifier ce type de calcul, mais ne peuvent pas simplifier les expressions ayant potentiellement un effet de bord. Par exemple, ils ne peuvent pas factoriser les appels de méthode.


double prixTTC1 = prix1*getTVA();

double prixTTC2 = prix2*getTVA();

Dans ce cas, il faut optimiser les expressions à la main.


double sousexpr = getTVA();

double prixTTC1 = prix1*sousexpr;

double prixTTC2 = prix2*sousexpr;

4-Déplacement de code

Cela consiste à détecter les codes dont le résultat ne varie pas et à le déplacer en dehors des boucles.


for (int i=0 ; i < x.length ; ++i)

xi = Math.PI Math.cos(y);

devient


double sousexpr = Math.PI Math.cos(y);

for (int i=0 ; i < x.length ; ++i)

xi = sousexpr;

5-Inversez l’ordre d’exécution d’une boucle

Si l’ordre de traitement d’une boucle n’a pas d’importance, il est préférable de l’inverser pour pouvoir comparer la condition de sortie par rapport à la constante zéro.

for (int i=0;i<array.length;i++)

devient

 
for (int i=array.length-1;--i>=0;) { ... }

La machine virtuelle de Java, comme tous les microprocesseurs, possède des instructions spécifiques pour comparer un entier avec la constante zéro. Le code est ainsi plus court et plus rapide.

6-Utiliser correctement la concaténation des String

La description de la méthode toString() explique comment utiliser correctement l’addition de deux chaînes de caractères. Cela permet de réduire le nombre de copies de tampon. Chaque fois que vous utilisez l’opérateur += avec une chaîne, vous dupliquer le tampon.

En choisissant correctement la taille du StringBuffer, vous améliorez également les performances. En effet, lorsqu’un caractère ne peut plus être ajouté, l’instance doit créer un nouveau tableau plus grand, et recopier tous les éléments. Cela peut s’effectuer plusieurs fois lors d’un traitement. En initialisant la taille du tampon, on évite ces recopies.

7-Ordonnez les variables

Contrairement aux langages compilés, l’accès aux variables dépend de leurs localisations. Une variable locale est plus rapide qu’une variable statique qui est plus rapide qu’une variable d’instance.

Les quatre premières variables locales utilisent un code optimisé. Il faut organiser les variables pour déclarer en premier les plus utilisées. Les bons compilateurs sont capables de détecter cela.

De même, il ne faut pas hésiter à dupliquer une variable d’instance dans une variable locale si elle est beaucoup utilisée dans un algorithme. Le résultat pourra retourner dans la variable d’instance lorsque tout sera terminé.

Ensuite un set des astuces globales et qui résident des bonnes pratiques de OO :

10-Choisissez le bon type

Java propose différents types primitifs plus ou moins précis. Ils se différencient par la place prise en mémoire et les valeurs minimums et maximales autorisées. Vous pouvez utiliser les types char ou byte dans des instances étant présentes en de nombreux exemplaires dans la mémoire. Le code nécessaire à la manipulation de ces types est plus important (le fichier .class est plus grand), mais cela est compensé par les économies réalisées sur chaque instance. De même, utilisez float à la place de double si la précision nécessaire le permet.

11-Libérez les ressources

La méthode finalize() peut s’occuper de libérer les ressources nécessaires à un objet. Cette méthode est appelée par le ramasse-miettes lorsque l’instance n’est plus nécessaire. Cela peut intervenir bien après la perte de l’objet. Il est préférable de gérer explicitement les ressources par un appel à close(), par exemple lorsqu’un flux n’est plus nécessaire.

12-Utiliser l’optimisation du compilateur

Pour optimiser le temps de chargement d’une application java, il faut réduire la taille du code généré. Utilisez javac -O . Si votre programme utilise souvent des méthodes en ligne, la taille du code généré peut être réduit en évitant les différents appels. Il faut comparer le résultat avec et sans l’option.

13-Utilisez l’héritage

Utilisez l’héritage pour factoriser un maximum de code. Cela évite les redondances et réduit le risque d’erreurs. Par exemple, séparez le code non portable dans des sous-classes.

14-Supprimer les méthodes inutiles

De nombreuses méthodes ne sont présentes que pour le déverminage. Par exemple, la plupart des classes possèdent une méthode main() afin de pouvoir effectuer les tests unitaires. Ces méthodes ne sont pas nécessaires à l’application. Vous pouvez séparer les méthodes de tests dans une autre classe, suffixé par exemple de UnitTest. Ainsi, il est facile de supprimer tous les fichiers UnitTest.class de l’archive avant de la publier sur le réseau.

Finalement, Ne pas optimiser si on ne sait pas si c’est nécessaire. Si vous voulez optimiser, commencez par modifier l’algorithme.

Avant d’effectuer une optimisation de bas niveau, mesurez le code pour voir où cela est nécessaire. Analysez le par la suite pour voir les impacts des modifications.

Reference: l’article de Philippe Prados

Publicités

3 Réponses to “Java Optimisation Tips”

  1. Salem Ben Afia novembre 30, 2011 à 8:26 #

    Joli résumé pour Best practices! juste une petite proposition: Si nous appliquons le point 3) au point 5) ça donne:

    int count=array.length()-1;
    for(int i=count; –i>=0;){…};

    • Florian octobre 10, 2012 à 2:49 #

      Bonjour, le billet est un peu vieux mais je me permets une remarque.

      Je pense qu’il y a une erreur dans le point 5 :
      Les deux boucles ne sont pas équivalentes.
      Exemple :
      Avec array.length = 5
      for (int i=0;i=0;) donne 3,2,1,0, il manque donc un élément.

  2. Florian octobre 10, 2012 à 2:51 #

    Bonjour, le billet est un peu vieux mais je me permets une remarque.

    Je pense qu’il y a une erreur dans le point 5 :
    Les deux boucles ne sont pas équivalentes.
    Exemple :
    for (int i=0;i=0;) donne 3,2,1,0, il manque donc un élément.

    Désolé pour le double post mais il y a eu une erreur la première fois.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :