Java Language Mémoire et surcharge de calcul de l'autoboxing


Exemple

L’autoboxing peut avoir une surcharge de mémoire importante. Par exemple:

Map<Integer, Integer> square = new HashMap<Integer, Integer>();
for(int i = 256; i < 1024; i++) {
    square.put(i, i * i); // Autoboxing of large integers
}

consommera généralement beaucoup de mémoire (environ 60 kb pour 6 k de données réelles).

De plus, les entiers encadrés nécessitent généralement des allers-retours supplémentaires dans la mémoire, ce qui rend les caches de processeur moins efficaces. Dans l'exemple ci-dessus, la mémoire accédée est répartie sur cinq emplacements différents qui peuvent se trouver dans des régions entièrement différentes de la mémoire: 1. l'objet HashMap , 2. l'objet Entry[] table , 3. l'objet Entry , 4. le entrys key object (boxing la clé primitive), 5. l'objet entry value (encadrant la value primitive).

class Example {
  int primitive; // Stored directly in the class `Example`
  Integer boxed; // Reference to another memory location
}

La lecture en boxed nécessite deux accès mémoire, n'accédant qu'à une primitive .

Lorsque vous obtenez des données de cette carte, le code apparemment innocent

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
    sumOfSquares += square.get(i);
}

est équivalent à:

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
    sumOfSquares += square.get(Integer.valueOf(i)).intValue();
}

En général, le code ci-dessus provoque la création et la récupération de Integer un objet Integer pour chaque opération Map#get(Integer) . (Voir la note ci-dessous pour plus de détails.)

Pour réduire ce surcoût, plusieurs bibliothèques offrent des collections optimisées pour les types primitifs ne nécessitant pas de boxe. En plus d'éviter la surcharge de boxe, ces collectes nécessiteront environ 4 fois moins de mémoire par entrée. Bien que Java Hotspot puisse optimiser l'autoboxing en travaillant avec des objets sur la pile au lieu du tas, il n'est pas possible d'optimiser la surcharge de mémoire et l'indirection de mémoire qui en résulte.

Les flux Java 8 ont également des interfaces optimisées pour les types de données primitifs, tels que IntStream qui ne nécessitent pas de boxe.

Remarque: un environnement d'exécution Java classique conserve un cache simple d' Integer et des autres objets wrapper primitifs utilisés par les méthodes factory valueOf et par la création automatique de boîtes aux lettres. Pour Integer , la plage par défaut de ce cache est comprise entre -128 et +127. Certaines machines virtuelles Java offrent une option de ligne de commande JVM pour modifier la taille / plage du cache.