27 octobre 2006

Mot clé "final" sur les méthodes: gain de performances?

En inspectant le code de mes développeurs, je remarque par-ci, par-là des méthodes "taggées" avec le mot clé "final". Et c'est une très mauvaise pratique!

La fonction principale de ce mot clé est d'empêcher la surcharge de cette méthode dans les classes filles. Etant donné que Java est un langage objet, et que l'on ne connaît pas les développements futurs, ce n'est pas une bonne idée d'utiliser final, cela réduit les possibilités d'extension de notre appli (sauf si c'est réellement voulu, mais c'est relativement rare).


Pendant un temps, lorsque l'on était à la version Java 1.2 à peu près, il a été dit que cela améliorer "magiquement" les performances (c'est-à-dire de meilleures perfs sans aucun désavantage).
Voilà pourquoi: ce mot clé sert à dire au compilateur qu'il peut éventuellement passer la méthode en mode "inline", c'est-à-dire que pendant la compilation, le compilateur peut, s'il le souhaite, insérer le corps complet de la méthode dans le flot d'instructions bytecode au lieu de l'appel standard de méthode (mise des arguments sur la pile, saut du pointeur courant vers le bytecode de la méthode, exécution, retour au flot courant et nettoyage de la pile).
Cependant il faut savoir que maintenant, le compilo et la JVM Hotspot sont extrèmement optimisés (statiquement et dynamiquement); si bien que:

- le compilateur sait très bien quand faire passer des méthodes en inline (généralement, ce sont des méthodes simples, de moins de 4 instructions); donc il y a de grandes chances (c'est même sûr) qu'il ignore "final" pour les méthodes de plus de 3 ou 4 instructions
- le compilateur peut de lui-même et intelligemment décider d'inliner (ou "incorporer) certaines méthodes, même si vous n'avez pas utilisé "final"
- Enfin, les optimisations dynamiques vont compiler en langage machine bas niveau (assembleur) les méthodes les plus utilisées; si bien que le code en mode "inline", qui est intégré au flux et qui court-circuite l'appel standard de méthode ne sera jamais optimisé (je simplifie un peu...). Donc au lieu de gagner en performance grâce à cette optimisation, on ne fait rien --> cela a l'effet inverse souhaité: de moins bonnes performances (c'est relatif puisque comme je viens de l'écrire, dans les faits le compilateur ignore votre "final" pour l'inline; il ne le prend en compte que pour le verrouillage de la surcharge).

Bref, "final" a une utilité bien particulière dans la sémantique du langage (bloquer la surcharge), et la légende sur l'amélioration des performances est un mythe (depuis au moins Java 1.3).


Au passage, j'ai trouvé un article (en anglais), qui décrit mieux que moi les cas d'utilisation utiles du mot clé final sur les méthode:
http://www-128.ibm.com/developerworks/java/library/j-jtp1029.html

1 commentaire:

Gabriel Kastenbaum a dit…

Ok. En revanche le final a un sens avec les pojo, qui doivent transporter de l'information.