J'essaie un point de repère de performance concernant la piscine à cordes. Cependant, le résultat n'est pas attendu.
J'ai fait 3 méthodes statiques p>
Mon attente était (1. Le plus rapide -> 3. Plus lent) P>
Mais le repère montre que "Te" + "ST" est légèrement plus rapide que "Test". P>
import java.util.concurrent.TimeUnit; public class StringPoolPerformance { public static long perform0() { long start = System.nanoTime(); for (int i=0; i<1000000; i++) { String str = new String("Test"); } return System.nanoTime()-start; } public static long perform1() { long start = System.nanoTime(); for (int i=0; i<1000000; i++) { String str = "Test"; } return System.nanoTime()-start; } public static long perform2() { long start = System.nanoTime(); for (int i=0; i<1000000; i++) { String str = "Te"+"st"; } return System.nanoTime()-start; } public static void main(String[] args) { long time0=0, time1=0, time2=0; for (int i=0; i<100; i++) { // result time0 += perform0(); time1 += perform1(); time2 += perform2(); } System.out.println("new String(): " + time0 + " ns"); System.out.println("\"Test\" : " + time1 + " ns"); System.out.println("\"Te\"+\"st\" : " + time2 + " ns"); } }
5 Réponses :
qui est facilement prouvé en désassemblant votre classe de référence compilée en utilisant "te" + "st" code> est une expression constante du temps compilateur, et donc se comportera à l'exécution
javap -c stringpoolformance code>: p>
public static long perform1();
Code:
...
7: ldc #3; //int 1000000
9: if_icmpge 21
12: ldc #5; //String Test
14: astore_3
15: iinc 2, 1
...
public static long perform2();
Code:
...
7: ldc #3; //int 1000000
9: if_icmpge 21
12: ldc #5; //String Test
14: astore_3
15: iinc 2, 1
...
La course pour TE + ST est également probablement plus rapide car l'optimisation de la performance1 est immédiatement utilisée par le spectacle2 (puisqu'elles sont exactement les mêmes).
Peut-être que le compilateur JIT commence et le troisième exécute du code natif. Peut-être que la concaténation a été déplacée à l'extérieur de la boucle. Peut-être que la concaténation n'est jamais terminée car la variable n'est jamais lue. Peut-être que la différence est le bruit et vos trois échantillons de coïncidence pointe de la même manière. P>
Benchmarking robuste Java, partie 1: Problèmes Explique beaucoup de façons que la benchmarking Java peut aller mal. P>
L'analyse comparative est extrêmement difficile. De nombreux facteurs, à la fois évidents et subtils, peuvent affecter vos résultats. Pour obtenir des résultats précis, vous avez besoin d'une commande approfondie de ces problèmes, éventuellement en utilisant un cadre d'analyse comparative qui en aborde. Aller à Partie 2 Pour en savoir plus tellement robuste Cadre de référence Java. P> blockQuote>
Ne vous attendez pas à ce que les micro-repères du code Java vous disent quelque chose d'utile jusqu'à ce que vous comprenez les pièges spécifiques que l'architecture JVM introduit et ne vous attendez pas à ce que même les meilleurs micro-repères prédisent la performance d'une application réelle. p>
Je ne sais pas quel est votre objectif, mais apprendre à utiliser un bon profileur et l'utiliser sur votre application réelle vous dira généralement si la ligne en question est vraiment la source d'inefficacité et vous permettra de mesurer l'effet d'un changement de code. Temps passé à apprendre qu'un profileur est probablement mieux dépensé que le temps écrit et déboguer des micro-repères. P>
Il n'y a pas de concaténation (runtime).
@Hotlicks, comment savez-vous? La spécification de la langue n'exige pas que les expressions constantes soient pliées par le compilateur lorsqu'il n'est pas utilisé lorsqu'une expression constante est requise.
@Hotlicks, je sais quelle expression constante est, mais il n'y a aucune obligation que Javac code> est pliant constant dans des contextes où des expressions sont attendues et que l'expression est également une expression constante.
C'est dans la priorité inhérente à la grammaire BNF.
@Hotlicks, vous avez raison (bien que ce ne soit pas inhérent à la grammaire). 15.18.1 Corder la concaténation opérateur b> dit explicitement "" Le résultat est une référence à un objet de chaîne ( nouvellement créé, à moins que l'expression soit une expression constante de la compilation i>) qui est la concaténation des deux Cordes d'opérande "
Tout d'abord, il serait bien de savoir que:
Si vous rencontrez des chaînes de concaténage, disons dans une boucle, alors vous savez que parce qu'ils sont immuables, de nouvelles chaînes continuent à être générées. Le compilateur Javac utilise à l'interne un Stringbuffer pour le faire, par exemple, vous avez P> blockQuote>
xxx pré> dans une boucle. p>
Que se passe-t-il, dans la boucle, deux objets sont générés. L'un est un stringbuffer - p> blockQuote>
xxx pré> L'autre est la chaîne qui est attribuée à itemlist via la totring (). ` p> blockQuote>
Source: http: // pensé -Bytes.Blogspot.com/2007/03/java-string-string-performance.html P>
Je pense que cela ne s'applique pas à votre cas. Dans le premier test de performance, vous créez toujours un nouvel objet afin de créer 1000000
chaîne ("test") code> objets. Dans les deuxième et troisième exemples, il n'y a créé qu'un seul objet à qui est pointé par de nombreux référencés. Comme cela a été dit avant:
"te" + "st" code> a été traité comme une constante de temps de compilateur et des différences sont trop petites pour dire qu'il est plus rapide que "Test". P> P>
Mark Peters a raison, deux constantes de cordes seront concaténées sans pitié. P>
Ceci est dû à la période de copie nécessaire pour concaténer des objets de chaîne, après leur taille. P>
Maintenant, celles-ci sont compilées dans des objets Stringbuffer / StringBuilder par le compilateur, vous pouvez le voir en décompilant un fichier .class. p>
Vous devez jeter un coup d'œil à ces classes, mais attention à ce que lorsque vous rendantez une chaîne StringBuilder ou Stringbuffer en tant que chaîne, un nouvel objet à chaîne sera créé. P>
@Bartoszkp ok je suis trop rapide écrit cela, "exponentiel" est un terme déterminant. Je modifie ma réponse.
@Bartoszkp (coincé par le délai de 5 minutes pour modifier le commentaire) Vous avez raison, "exponentiel" est un terme certainement incorrect! Je modifie ma réponse, merci d'être attentif à de telles erreurs.
Désolé de poster une réponse, mais je ne pouvais pas mettre cela dans un commentaire pour montrer à quel point cette référence est défectueuse. Sur Linux, j'ai changé l'ordre et obtenez:
La commande importe de manière défiant. P>
Le compilateur ne doit-il pas combiner deux constantes?
Strings "Te", "ST" est littéral, alors le compilateur les modifierait-il pour "tester" en phase d'optimisation? Je ne sais pas
Changez la commande que vous appelez Effectuer1 et exécutant2 et voyez si vous obtenez toujours les mêmes résultats.
Il peut y avoir un attente de fil en raison d'un commutateur de contexte
Vous voudrez peut-être lire ceci: Anatomie d'une microbenchmark défectueux a>
Courir sur OS X 10.8 a des résultats similaires.
String Str = "T" + "E" + "S" + "T" code> est même légèrement plus rapide!
À tout le moins, le programme doit exécuter la même séquence de test une seconde fois et jeter le premier ensemble de résultats, pour que les choses soient assez bien jitées et obtenir le tas "réchauffé". Sans que les résultats sont assez significatifs.