<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Artisan Numérique</title>
  <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1528"/>
  <link rel="self" type="application/atom+xml" href="http://artisan.karma-lab.net/node/1528/atom/feed"/>
  <id>http://artisan.karma-lab.net/node/1528/atom/feed</id>
  <updated>2008-07-30T15:38:34+02:00</updated>
  <entry>
    <title>Java, les coûts de l&#039;optimisation</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1528" />
    <id>http://artisan.karma-lab.net/node/1528</id>
    <published>2008-06-17T00:05:09+02:00</published>
    <updated>2008-07-30T15:38:34+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="java" />
    <category term="drupalfr.org" />
    <category term="OK" />
    <category term="Planet Libre" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p>
  Dame Java, plus que toute autre plate-forme, trimbale avec elle une ribambelle d'idées reçues au regard de ses performances. Cela va du bête et simple "Java c'est lent" qui date des JDK 1.2 et 1.3, à des optimisations de code exotiques en droite ligne des croyances C/C++. L'objectif de cet article est donc de poser des valeurs chiffrées sur certains de ces mythes pour déterminer s'ils en sont, ou pas. Et des fois, cela révèle de belles surprises. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
  Dame Java, plus que toute autre plate-forme, trimbale avec elle une ribambelle d'idées reçues au regard de ses performances. Cela va du bête et simple "Java c'est lent" qui date des JDK 1.2 et 1.3, à des optimisations de code exotiques en droite ligne des croyances C/C++. L'objectif de cet article est donc de poser des valeurs chiffrées sur certains de ces mythes pour déterminer s'ils en sont, ou pas. Et des fois, cela révèle de belles surprises. 
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Protocole de test</h2>
	
<p>
  Lorsque l'on fabrique des micro-benchmarks, l'ennemi c'est HotSpot. Pour ceux qui voudraient s'y frotter, je vous conseille à ce sujet l'exellemnt article (en anglais) : <a class='external' target='_blank' href='http://www-128.ibm.com/developerworks/java/library/j-jtp02225.html?ca=drs-j0805' >Anatomy of a flawed microbenchmark</a>. 
</p>
<p>
 En effet le bougre est tellement doué qu'il a vite fait de fausser les résultats par un tour de passe-passe en détectant que telle ou telle partie de code n'est pas utilisée. Tous les tests qui sont fait ici sont donc clôturés par un test de sorte à s'assurer qu'HotSpot ne nous joue pas de tours. 
</p>
<p>
De plus pour réduire encore les aléas, chaque benchmark est lancé 10 fois de suite et seul le meilleur résultat est gardé (merci shimrod <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>. A chaque lancement de test, le garbage collector est vidé (autant que faire se peut), et les cache disques sont ré-initialisés.
</p>
<p>
Enfin, tout se fait de manière automatique dans une infrastructure maison très proche de JUnit de sorte à ne privilégier personne. Les graphiques sont ainsi générés automatiquement à l'issue de chaque test. 
</p>

	<a name='chapter_2'></a>
  <h2>Influence du -server</h2>
	
<p>
  <image file="VMOptions.png"/>
  Tant que l'on est dans le domaine de HotSpot, il est intéressant de jeter un œil sur une optimisation des plus directe, à savoir d'utiliser la VM dans son profil "serveur". Pour ce test, un calcul de la valeur de PI à 100 chiffres sert de base de travail et le résultat est pour le peu étonnant. 
</p>
<p>
  Le mode -server indique à la VM, et particulièrement à HotSpot, d'optimiser dès le démarrage tout ce qu'il peut. Ce à quoi cela correspond exactement reste assez obscur, certains disent qu'HotSpot pré-compile l'ensemble du code, d'autres qu'il détecte les chemins efficaces en avance de phase (c'est à dire avant d'avoir à les exécuter réellement). Au fond peu importe, ce qui est sûr c'est que les performances sont meilleures avec cependant une contrepartie à garder en tête. 
</p>
<p>
Sur le graphique, les barres indiquent les temps d'exécution du calcul de PI pour les deux modes, la ligne représente elle le temps de démarrage par mode. Ce que l'on constate donc c'est que si le gain de performance est réel, le temps d'exécution lui, a augmenté significativement. C'est donc la première contre-partie. La seconde étant que ce mode est réputé consommer plus de mémoire. 
</p>
<p>
 En somme, le mode "server" est bien adapté à des applications aillant une longue durée de vie. Les applications devant démarrer vite et avec peu de mémoire préféreront le mode "client". 
</p>

	<a name='chapter_3'></a>
  <h2>Copie de tableau</h2>
	
<p>
<image file="ArrayCopy.png"/>
   Cette vieille histoire de copie de tableaux est une bonne manière d’illustrer les évolutions qu'à connues la VM depuis ces débuts. En effet, la bonne réputation de System.arrayCopy s’est faite à l’époque du JDK 1.4 où elle obtenait des scores deux à trois fois supérieurs à une recopie par itérative.</p>
<p>
 Avec les JDK 6 et 7 (graphique ci-contre) les choses ont bien changé. ArrayCopy reste rapide mais la différence est devenue très faible alors que le test porte tout de même sur un tableau de 20 millions d'entiers de type <kbd>long</kbd>...  L'autre aspect intéressant de ce résultat est que System.arrayCopy est une méthode native, c'est à dire écrite en C. Cela illustre donc assez bien les différences réelles de performance entre une VM moderne et un code compilé nativement. 
</p>
<div class='inline-box note'>Sous Windows, pour une raison que j'ignore, la différence entre les deux méthodes est beaucoup plus importante que sous Linux.</div>



	<a name='chapter_4'></a>
  <h2>Entrées/Sorties</h2>
	
<p>
<image file="BufferedStreams"/>
Dés qu’il s’agit d'entrées-sorties, que ce soit pour un fichier ou pour un flux réseau, la règle d’Or est « tampon ». Certains vont trouver cela un peu naïf comme conseil mais la réalité du code que j’ai régulièrement sous les yeux tend à prouver que ce n’est pas une évidence pour tous et les cas de lecture ou écriture dans un input/output stream tout con, et ce tant qu'à faire, octet par octet, sont légions. Le graphique ci-contre donne une bonne idée de l’impact de cette approche sur les performances. 
</p>
<p>
La raison est toute simple. Nombre de périphériques fonctionnent par bloc, et donc par tampon. Forcer une lecture-écriture octet par octet sur un disque où une interface réseau revient à court-circuiter ce mécanisme en obligeant le matériel à vider des tampons quasi vides. Et se traduit par une perte drastique de performance. 
</p>
<p>
La solution la plus simple consiste à systématiquement encapsuler un input/output <kbd>stream</kbd> dans un <kbd>BufferedInputStream</kbd> ou <kbd>BufferedOutputStream</kbd>.</p>

<p style="clear:left">
<image file="NIO.png"/>Ensuite il est possible d'améliorer encore les performances en utilisant la librairie NIO disponible depuis le JDK 1.4. Comme vous les voyez les résultats sont très bon mais le code beaucoup plus complexe.</p>
<p>
 D'un point de vue général, la bonne position est de toujours passer par un buffer, et autant que possible écrire par block dans ce buffer
</p>


	<a name='chapter_5'></a>
  <h2>Méthodes finales</h2>
	
<p>
  <image file="FinalMethod.png"/> Toute personne à qui j'ai demandé à quoi servait le mot clef <kbd>final</kbd> a du me sortir une version différente de l'histoire. Dés fois c'est juste "joli", d'autre cela fait gagner de la mémoire, cela protège les fonctions/classes, d'autre fois encore cela rend tout plus rapide. Après avoir pas mal cherché car moi non plus je n'avais pas la réponse, je me suis rendu compte que c'est le camp de la "mémoire" qui avait raison, avec celui de la protection, un peu. Mais pour la performance, comme vous pouvez le constater, ça change que dalle... 
</p>


	<a name='chapter_6'></a>
  <h2>Position de la constante dans un test</h2>
	
<p>
<image file="ConstantPositionInCondition.png"/>
  Je ne sais pas de quant date cette drôle de mode, sûrement des âges lointains du C, mais j'ai rencontré un nombre de fois incalculable des développeurs qui s'acharnaient à écrire des choses comme 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw2">null</span><span class="sy0">==</span>maValeur<span class="br0">&#41;</span> <span class="br0">&#123;</span> <br />
...<br />
&nbsp;<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
L'argument auquel j'ai souvent eu droit est que cette approche est beaucoup plus performante pour une raison obscurément liée au nombre de la bête. Mais comme en témoigne le graphique, c'est un mythe cyberurbain de plus. La position de la constante n'a aucune sorte d'importance et ce serait autrement lisible par un humain de base si s'était écrit dans le "bon" sens. 
</p>
<p>
Il en va de même pour les fanatiques du <kbd>++compteur</kbd> qui n'apporte strictement rien sur le naïf <kbd>compteur++</kbd> lisible par n'importe quel quidam, moi compris. pour info, le test a été répété 5 millions de fois pour obtenir ce pouillème de différence sûrement due à un ou deux quarks en vadrouille sur mon CPU ce jour là. 
</p>


	<a name='chapter_7'></a>
  <h2>Les exceptions</h2>
	
<p>
<image file="TryCatch.png"/>
Là ce n'est plus un mythe, ou plutôt ce n'en était pas un. En effet, les blocks try/catch ont souvent été à juste titre pointés comme une source de fuite de performance. Et force est d'avouer que la VM a énormément évolué depuis pour obtenir aujourd'hui d'aussi une si petite différences sur des tests itérés 1 million de fois...
</p>
<p>
 En somme, si votre programme broute, ce n'est pas la peine de virer la gestion des exceptions...
</p>



	<a name='chapter_8'></a>
  <h2>Condition d'une boucle</h2>
	
<p>
<image file="LoopOptimisation.png"/>
  Autant la position d'une constante dans un test n'a, comme nous l'avons vu, strictement aucune incidence sur les performances, autant la condition dans une boucle de type <kbd>for</kbd> ou <kbd>while</kbd> peut avoir des conséquences désastreuses. Et c'est au fond une question de bon sens car cette condition est exécutée autant de fois que la boucle fait de tous. Ainsi, si vous écrivez une boucle comme dans l'exemple suivant, à chaque itération, la fonction <kbd>calculeValeurMax</kbd> est exécutée.

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i<span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0">&lt;</span> calculeValeurMax<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> i<span class="sy0">++</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
...<br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>
<p>
   Et si cette fonction prend disons 50ms à renvoyer son résultat, une boucle de 1000  itérations, coûtera 50 secondes juste pour le test... La solution est dans ce cas d'inverser la tendance pour placer la fonction coûteuse dans une zone fixe. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">for</span> <span class="br0">&#40;</span><span class="kw4">int</span> i<span class="sy0">=</span>calculeValeurMax<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="nu0">-1</span><span class="sy0">;</span> i<span class="sy0">&gt;=</span><span class="nu0">0</span><span class="sy0">;</span> i<span class="sy0">--</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
...<br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>


	<a name='chapter_9'></a>
  <h2>Taille des identifiants</h2>
	
<p>
<image file="IdentifiantSize.png"/>
  Repassons un peu sur de la bonne légende urbaine maintenue vivace par la guilde des compresseurs de code. Cette catégorie de gens ont un métier qui s'approche plus de la cryptographie que du développement tant ils aiment à produire un code bien compact en persuadant leur entourage que plus c'est court, plus ça va vite. Ces gens là, on les comprend, détestent les formateurs automatique de code et se vengent sur la taille des identifiants en les réduisant au maximum à un ou deux caractères arguant que de longues variables influent sur les performances. 
</p>
<p>
  Dans l'exemple du graphique, j'ai une variable qui fait à peu prés 255 caractères contre une de 1 caractère. Comme vous le voyez, sur 500 millions d'itérations la différence est flagrante... Et pour cause, le compilateur Java stocke les identifiants, toutes tailles confondues, dans un dictionnaire en tête du bytecode de la fonction et ne les utilise plus que par référence en interne. Il n'y a donc aucune raison autre que religieuse à produire un code illisible ou utiliser des abréviations compréhensible des seuls initiés. 
</p>

	<a name='chapter_10'></a>
  <h2>Objets mutables et immutables</h2>
	
<p>
<image file="MutableImmutable.png"/>
Un objet est dit "immutable" si l'on ne peut pas en changer la valeur interne. Par exemple String est immutable. Si l'on veut changer la chaîne de caractère qu'il contient nous sommes obligés de créer un nouvel objet. A contrario, StringBuffer est un objet mutable. Je peux le vider de son contenu ou l'étendre. 
</p>
<p>
Une des raisons des gros problèmes de performances de Swing à ces débuts tenait justement à ce que des objets élémentaires comme Point ou Dimension étaient immutable, obligeant ainsi la VM à créer des objets en pagaille à chaque modification. Aujourd'hui la coordonnées X d'un point est modifiable par <kbd>p.x</kbd> avec du coup un réel gain de performance. 
</p>
<p>
Le graphique ci-contre illustre la différence d'approche mutable/immutable pour donner une idée des différences de performance. L'immutabilité est donc à utiliser avec parcimonie lorsqu'elle est réellement justifiée (intégrité du contenu par exemple). 
</p>

	<a name='chapter_11'></a>
  <h2>Synchronisation</h2>
	
<p>
<image file="Synchronized.png"/>
  La synchronisation est un mécanisme permettant à une même ressource d'être utilisée sans conflits par plusieurs processus (thread). Ainsi lorsqu'un traitement est synchronisé sur un objet, cet objet n'est disponible que pour le premier arrivant, les suivants sont mis en attente jusqu'à ce que la ressource soit libérée, et ainsi de suite. 
</p>
<p>
  Les blocs synchronisés, comme les Exceptions vues plus haut, ont longtemps été une source de perte de performance en Java. Il y a donc dans le JDK des versions synchronisées (dits thread-safe) et non-synchronisées pour une même fonction. C'est le cas de Hashtable (synchronisé) et Hashmap (non synchronisé), Vector (synchronisé) et ArrayList (non synchronisé). 
</p>
<p>
Il serait donc logique de se dire qu'il est important d'utiliser les versions non-synchronisées aussi souvent que possible. Mais le problème est qu'avec une VM moderne (JDK6/7), comme pour les Exceptions, les blocs synchronisés représente un coût négligeable. Le graphique ci-contre en témoigne et le nombre d'itération utilisé pour le construire est de 1 million...
</p>
<p style="clear:left">
<image file="HashMapHashTable.png"/>
Or aujourd'hui, avec le développement massif des processeurs à 2 ou 4 cœurs, les applications gagnent réellement à être massivement parallélisées. Utiliser une structure qui ne soit pas "thread safe" c'est prendre le risque de passer des heures à chercher les verrous mortels lorsque vous serez amenés à "threader" votre code.
</p>
<p>
 Le second graphique d'exemple compare justement un Hashmap de 800 milles éléments à ses équivalents Hashtable et ConcurrentHashmap. Comme vous le voyez, le jeu n'en vaut clairement plus la chandelle avec même une petite avance pour ConcurrentHashmap. Et le résultat est strictement le même entre Vector et ArrayList. 
</p>
<p>
Alors vu l'enfer que représente d'un debuggage multi-thread, pensez-y à deux fois avant de jouer la carte de ce genre d'optimisation. 
</p>


	<a name='chapter_12'></a>
  <h2>Les entiers</h2>
	
<p>
<image file="IncDec.png"/>
Une idée communément répandue est de dire que plus petite est la structure, meilleur sont les performances. Ainsi il est courant de voir des compteurs de boucles "taillées au plus juste", genre en utilisant un <kbd>byte</kbd>. Le problème est que dans la vraie vie les choses se passent autrement car c'est la matériel qui compte. Et il y a longtemps que les CPU ne manipulent plus des entiers de 8bits, mais plutôt de 32 ou 64 bits. La conséquence est que pour les opérations de comptage (Inc/Dec et Add/Sub), le <kbd>byte</kbd> est systématiquement le mauvais choix de performance et <kbd>int</kbd> le meilleur alors qu'il est 4 fois plus gros. Et pour les mêmes raisons sur les processeur modernes, un long (64 bits) est toujours et encore meilleur qu'un byte. </p>
<p style="clear:left">
<image file="AddSub.png"/>
A noter aussi que les opérateurs <kbd>++</kbd> et <kbd>--</kbd> sont plus rapides que leurs équivalent <kbd>+1</kbd> et <kbd>-1</kbd>. La aussi la raison en est que les processeurs disposent d'opérateurs d'incrémentation-décrémentation et que le bytecode, lui aussi, distingue ces deux cas. Du coup, sur un processeur moderne décrémenter ou incrémenter un compteur est à peu prés aussi performant sur un long que sur un int. 
</p>
<p>
  Maintenant il y a une autre raison beaucoup plus intéressante qui se trouve dans le bytecode lui-même. Prenons l'incrémentation d'une variable de type entier (i++), en byte code cela nous donne :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  IINC <span class="nu0">1</span><span class="sy0">:</span> i <span class="nu0">1</span>
  </div>
  
  </div>
</p>
<p>
  Maintenant regardons le bytecode de l'incrémentation d'un byte (b++) 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="sy0">//</span> Chargement de la valeur de b dans <span class="kw4">le</span> registre entier<br />
ILOAD <span class="nu0">1</span><span class="sy0">:</span> b<br />
<span class="sy0">//</span> Création d<span class="st0">'une constante 1<br />
ICONST_1<br />
// Ajout des deux<br />
IADD<br />
// Conversion de l'</span>entier en bytes<br />
I2B<br />
<span class="sy0">//</span> Stockage du <span class="kw5">byte</span><br />
ISTORE <span class="nu0">1</span><span class="sy0">:</span> b
  </div>
  
  </div>
</p>
<p>
  Étonnant non ? En fait lorsqu'une seule opération est nécessaire pour incrémenter notre entier, il en faut 5 pour incrémenter un byte. 
</p>



	<a name='chapter_13'></a>
  <h2>Variables locales contre champs</h2>
	
<p>
<image file="12"/>
Là aussi c'est un concept qui revient souvent. La variable locale serait plus rapide que la variable d'instance (le champ). Et pourtant, comme vous pouvez le voir, la différence est loin d'être flagrante et ce même en poussant à 1 milliard d'itérations. Même constat lorsque les variables sont finales ou statiques, cela ne change rien du tout. 
</p>

	<a name='chapter_14'></a>
  <h2>Getter ou pas getter</h2>
	
<p>
<image file="AssignementLocalField.png"/>
  Les accesseurs (getters et setters) emmerdent les développeurs, c'est bien connu <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/> Et pourtant ils ont une importance primordiale car ils offrent sécurité et  extensibilité. En effet, il est autrement plus simple d'ajouter des tests sur un <kbd>setValeur()</kbd> que sur un champ public que l'on a laissé "filé" dans la nature.</p>
<p> Mais comme souvent cette bonne pratique est contrée par des impératifs de performance. Le Getter ou le Setter, c'est un appel de fonction et donc un temps en plus qui va plomber l'application... 
</p>
<p>
En vérité c'est bien mal connaître M. HotSpot, le compilateur temps réel de Java, qui va arranger tout cela aux petits oignons pour obtenir les résultats du graphique qui se passent de commentaires. L'argument performance ne tient ici pas la route, le résultat est strictement le même. 
</p>


	<a name='chapter_15'></a>
  <h2>Les dimensions des tableaux</h2>
	
<p>
<image file="ArrayDimensions.png"/>
Encore une légende urbaine qui a la peau dure : plus un tableau a de dimensions, plus ça rame. Là aussi ce doit être un héritage que nous a laissé l'ancêtre C mais la réalité Java est tout autre. Le nombre de dimension n'a juste aucun impact sur les temps d'exécution. Donc autant faire rapidement un code propre plutôt que de se perdre dans des <kbd>buffer[y*largeur+x]</kbd> qui eux, coûtent du temps (celui du calcul de l'indice). 
</p>


	<a name='chapter_16'></a>
  <h2>Chaînes de caractère</h2>
	
<p>
<image file="StringConcatenation.png"/>
Comme nous l'avons vu plus haut, les String sont immutables, ce qui implique que lorsque l'on cherche à construire dans une boucle, une liste de 100 items séparés par des virgules, nous fabriquons en réalité au minimum 100 objets String. 200 même si les deux ajouts sont séparés. Autant dire que lorsqu'il s'agit de modifier une chaîne, comme l'illustre sans appel le graphique, il faut systématiquement passer par un <kbd>StringBuffer</kbd> qui est fait pour cela. 
</p>
<p style="clear:left">
<image file="StringFormater.png"/>
   L'exemple suivant est plus étonnant. Il s'agit de formater une chaîne composée d'un entier, une espace et une autre chaîne. Je me suis longtemps fait avoir en imaginant que le très pratique <kbd>String.format("%d %s", i, PATTERN)</kbd> était plus performant que <kbd>i+" "+PATTERN</kbd>. Belle erreur comme en témoigne le graphique ou les deux derniers cas font appel à ce fameux formateur. La concaténation à l'ancienne est donc préconisée lorsque l'on a aucun formatage évolué à mettre en œuvre. 
</p>


	<a name='chapter_17'></a>
  <h2>Cast et Generics</h2>
	
<p>
<image file="Cast.png"/>
  Les génériques étaient une évolution très attendue du JDK 1.5 permettant de typer un objet lors de son utilisation (<kbd>Vector&lt;Integer&gt;</kbd>). Il était donc intéressant de savoir si cette fonctionnalité avait un coût en terme de performance. Et le résultat semble être que non.</p>
<p>
 Et ce n'est pas si étonnant au fond car sans les génériques, nous étions obligés d'opérer un <kbd>cast</kbd> sur les valeurs d'un <kbd>Vector</kbd> par exemple pour pouvoir utiliser l'objet sous-jacent. 
</p>
<p style="clear:left">
<image file="Generic.png"/>
Avec les génériques ce cast est, un peu comme le C++, effectué à la compilation du code. Le gain entre les deux approches est donc à mettre au crédit de cet aspect comme en témoigne le second graphique qui mesure l'impact d'un cast sur le temps d'exécution.</p>
<p>
 Notez au passage que le cast classique <kbd>(MonObjet)maValeur</kbd> et par méthode <kbd>MonObjet.class.cast(maValeur)</kbd> ont le même coût.</p>
</p>

<p style="clear:left">
<image file="Generic.png"/>
Avec les génériques ce cast est, un peu comme le C++, effectué à la compilation du code. Le gain entre les deux approches est donc à mettre au crédit de cet aspect comme en témoigne le second graphique qui mesure l'impact d'un cast sur le temps d'exécution.</p>
<p>
 Notez au passage que le cast classique <kbd>(MonObjet)maValeur</kbd> et par méthode <kbd>MonObjet.class.cast(maValeur)</kbd> ont le même coût.</p>
</p>

<h3>AutoBoxing</h3>

<p style="clear:left">
<image file="NewValueOf.png"/>
Lorsque l'on manipule les versions Objet de types de base, comme <kbd>Integer</kbd>, une optimisation qui est souvent évoquée est de replacer <kbd>Integer i=new Integer(2)</kbd> par <kbd>Integer i=Integer.valueOf(2)</kbd>. Sur le graph, on se rend bien compte que la différence est, comment dire, assez négligeable... Mais ce qui est ici intéressant c'est que l'utilisation de l'AutoBoxing, c'est à dire quelque chose du genre <kbd>Integer i=2</kbd>, qui est une fonctionnalité apparue avec la version 1.5 de Java, est aussi rapide que les autres. 
</p>



	<a name='chapter_18'></a>
  <h2>Conclusion</h2>
	
<p>
Ce qu'il faut conclure de tout cela est tout d'abord que la VM a énormément évolué, gommant beaucoup de problèmes de performances (synchronisation, Exceptions, etc.). Ensuite que le code offusqué n'est en rien plus performant qu'un code clair. Enfin, qu'outre deux trois fondamentales comme l'utilisation des buffers (String ou IO) ou l'utilisation des entiers, aucune optimisation n'est réellement efficace. La meilleure manière d'optimiser reste d'écrire un code le plus clair possible et de lasser HotSpot faire au mieux son travail. Doublé d'une bonne dose de bon sens, cela devrait permettre d'obtenir le maximum d'efficacité. 
</p>    ]]></content>
  </entry>
</feed>
