Question

Pourquoi le deuxième morceau de code plus rapide?

Map<Integer, Double> map = new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {
        map.put(i, j);
    }
}

Map<Integer, Double> map=new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {            
        map.put(new Integer(i), new Double(j));
    }
}
Était-ce utile?

La solution

Autoboxing utilise Integer.valueOf, qui met en cache des objets à l'intérieur d'entiers pour les petits nombres entiers (par défaut -128 à 127, mais la valeur maximale peut être configurée avec la propriété « java.lang.Integer.IntegerCache.high » - voir le code source de Integer.valueOf), il est si différent de l'appel new Integer directement. Parce que Integer.valueOf effectue une vérification rapide pour l'amplitude de la valeur entière avant d'appeler new Integer, il est d'appeler directement new Integer un peu plus rapide (mais il utilise plus de mémoire si vous avez beaucoup de petits entiers). Allocation en Java est très rapide, et le temps de faire GC est proportionnel au nombre d'objets de courte durée en direct (à savoir pas proportionnelle à la quantité de déchets), de sorte que GC est également très rapide.

Mais selon la version JVM et qui optimisations sont activées, il est l'optimisation de remplacement scalaire, ce qui peut produire une différence de performances beaucoup plus lors de l'attribution des objets de courte durée (dans votre exemple que l'optimisation ne peut pas être fait, parce que vous stockez les objets dans une carte, mais il est dans beaucoup d'autres situations utiles).

Ces dernières versions JVM il est optimisation de remplacement scalaire ( sauf dans 1.6.0_18 où l'analyse d'évasion est temporairement désactivé), ce qui signifie que les allocations d'objets de courte durée peuvent être optimisés loin. Lorsque le remplacement scalaire dans JVM était nouveau, quelqu'un a une référence où il y avait un code similaire à la vôtre. Le résultat est que le code qui a utilisé des primitives était le plus rapide, le code des appels explicites new Integer() était presque aussi rapide que celle utilisant des primitives, et le code qui a utilisé autoboxing était beaucoup plus lent. En effet, autoboxing utilise Integer.valueOf et au moins à l'époque l'optimisation de remplacement scalaire n'a pas ce cas particulier en considération. Je ne sais pas si l'optimisation a été améliorée depuis.

Autres conseils

Autoboxing utilisera Integer.valueOf et Double.valueOf. Il y a certains frais généraux pour appeler ces méthodes (bien qu'il finira par se inline). Aussi Integer.valueOf fait quelques vérifications pour les faibles valeurs à utiliser les instances mises en commun, ce qui est souvent pas une victoire dans votre code (bien qu'il pourrait réduire la taille du tas un peu). cas peuvent être mis en commun une victoire où ils réduisent la taille du tas, GC fois et pourrait même améliorer les performances de test d'égalité ..

Mais, en général, il est un microoptimisation que vous devriez, en général, ne pas tenir compte.

Parce que les résultats de microbenchmarks ne sont pas fiables?

En outre, auto-boxing est effectuée à l'aide Integer.valueOf () et Double.valueOf (), et non pas les constructeurs.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top