Je suis à essayer de comprendre la capacité optimale et le facteur de charge d'un cas précis. Je pense que j'ai compris l'essentiel, mais je serais toujours reconnaissante pour une confirmation de quelqu'un de plus informé que moi. :)
Si je sais que ma table de hachage va se remplir à contenir, disons, 100 objets, et passent la plupart du temps avoir 100 objets, je devine que les valeurs optimales sont de capacité initiale de 100 et le facteur de charge 1? Ou dois-je besoin d'une capacité de 101, ou existe-il d'autres problèmes?
EDIT: OK, j'ai mis de côté quelques heures et fait quelques tests. Voici les résultats:
- Curieusement, la capacité, la capacité de+1, capacité+2, capacité-1 et de même capacité de 10 tous rendement exactement les mêmes résultats. Je m'attends au moins de la capacité-1 et capacité de 10 à donner de moins bons résultats.
- L'aide initiale de la capacité (par opposition à l'utilisation de la valeur par défaut de 16 ans) donne de la malformation put() de l'amélioration - jusqu'à 30% plus rapide.
- En utilisant le facteur de charge de 1 donne le même rendement pour le petit nombre d'objets, et de meilleures performances pour un plus grand nombre d'objets (>100000). Cependant, ceci n'améliore pas de manière proportionnelle au nombre d'objets; je soupçonne il y a un autre facteur qui influe sur les résultats.
- get() est un peu différente pour différents nombre d'objets/de la capacité, mais si cela peut légèrement varier au cas par cas, en général, il n'est pas affecté par la capacité initiale ou le facteur de charge.
EDIT2: Ajout de quelques diagrammes de ma part. Voici l'un illustrant la différence entre le facteur de charge 0,75 et 1, dans les cas où j'initialise HashMap et de le remplir à pleine capacité. Sur l'échelle y est de temps en ms (en bas c'est mieux), et x est l'échelle de la taille (nombre d'objets). Depuis les changements de taille linéaire, le temps nécessaire croît linéairement.
Donc, nous allons voir ce que j'ai. Les deux graphiques suivants montrent la différence dans les facteurs de charge. Premier graphique montre ce qui arrive quand HashMap est rempli à pleine capacité; facteur de charge de 0,75 effectue pire en raison de redimensionnement. Cependant, il n'est pas systématiquement le pire, et il y a toutes sortes de bosses et de houblon - je suppose que la GC est l'un des principaux enjeux dans ce. Facteur de charge de 1,25 effectue le même que le 1, il n'est donc pas inclus dans le graphique.
Ce graphique prouve que de 0,75 était pire à cause de redimensionnement; si nous remplir la table de hachage à la moitié de sa capacité, de 0,75 est pas pire, juste... différent (et il devrait utiliser moins de mémoire et ont unnoticably mieux itération de la performance).
Une chose que je veux montrer. Il s'agit d'obtenir des performances pour l'ensemble des trois facteurs de charge et les différents HashMap tailles. De façon constante constante avec un peu de variation, sauf pour un pic pour le facteur de charge 1. J'avais vraiment envie de savoir ce que c'est (probablement GC, mais qui sait).
Et voici le code pour ceux que ça intéresse:
import java.util.HashMap;
import java.util.Map;
public class HashMapTest {
// capacity - numbers high as 10000000 require -mx1536m -ms1536m JVM parameters
public static final int CAPACITY = 10000000;
public static final int ITERATIONS = 10000;
// set to false to print put performance, or to true to print get performance
boolean doIterations = false;
private Map<Integer, String> cache;
public void fillCache(int capacity) {
long t = System.currentTimeMillis();
for (int i = 0; i <= capacity; i++)
cache.put(i, "Value number " + i);
if (!doIterations) {
System.out.print(System.currentTimeMillis() - t);
System.out.print("\t");
}
}
public void iterate(int capacity) {
long t = System.currentTimeMillis();
for (int i = 0; i <= ITERATIONS; i++) {
long x = Math.round(Math.random() * capacity);
String result = cache.get((int) x);
}
if (doIterations) {
System.out.print(System.currentTimeMillis() - t);
System.out.print("\t");
}
}
public void test(float loadFactor, int divider) {
for (int i = 10000; i <= CAPACITY; i+= 10000) {
cache = new HashMap<Integer, String>(i, loadFactor);
fillCache(i / divider);
if (doIterations)
iterate(i / divider);
}
System.out.println();
}
public static void main(String[] args) {
HashMapTest test = new HashMapTest();
// fill to capacity
test.test(0.75f, 1);
test.test(1, 1);
test.test(1.25f, 1);
// fill to half capacity
test.test(0.75f, 2);
test.test(1, 2);
test.test(1.25f, 2);
}
}