Espace requis pour conserver le plus grand tableau d'entiers en mémoire
Je suis en train de passer en revue un algorithme et il conserve un tableau d'entiers, la taille de l'entrée est dynamique. Donc, selon mes calculs, cela peut prendre autant que
integer MAX_VALUE * int size = ?
2^31 integers * 4 bytes = ?
2147483648 integers * 4 bytes = 8 Gigabytes
Ce calcul est-il correct? la JVM utiliserait-elle cet espace très contigu pour stocker le tableau int ou y a-t-il d'autres choses à prendre en compte?
Réponses
La taille théorique du tableau serait:
numberOfElementsInTheArray * 4 octets
12 octets d'en-têtes (
int[]
est un objet). En fait, la taille des en-têtes dépend des indicateurs que vous avez utilisés et de la version JVM que vous exécutez4 octets pour garder le
length
du tableaurembourrage.
Par exemple: (je vais utiliser JOL pour cela ):
int [] x = new int[10];
for(int i=0;i<10;++i){
x[i] = 9999;
}
System.out.println(GraphLayout.parseInstance((Object)x).toPrintable());
affichera:
[I@7a81197dd object externals:
ADDRESS SIZE TYPE PATH VALUE
70fe45268 56 [I [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999]
Donc, il a 56 bytes
:
- 40 pour les valeurs elles-mêmes (10 pouces * 4 octets)
- 12 pour les en-têtes
- 4 pour la longueur
- 0 pour le rembourrage
Si vous modifiez ce tableau en Integer
, les choses changent radicalement. Integer
est un objet, vous allez donc stocker une référence à l'intérieur du tableau (qui pourrait être 4
ou 8
octets, selon l' UseCompressedOops
indicateur), plus chacune des Integer
instances nécessitera 2 en-têtes (chacun Integer
est un objet).
Integer[] y = new Integer[10];
for(int i=0;i<10;++i){
y[i] = 9999;
}
System.out.println(GraphLayout.parseInstance((Object)y).toFootprint());
qui montrera:
[Ljava.lang.Integer;@369f73a2d footprint:
COUNT AVG SUM DESCRIPTION
1 56 56 [Ljava.lang.Integer;
10 16 160 java.lang.Integer
11 216 (total)
Un total de 216 bytes
:
- 4 octets pour chaque référence (j'ai
UseCompressedOop
activé), 40 octets au total - 12 octets en-têtes du tableau
- 4 octets de longueur du tableau
- 0 octets de remplissage
Chaque référence de ce tableau pointe vers un Integer
, chacun de ces objets aura 16 bytes
:
- 4 octets pour l'intérieur
int
qu'ils détiennent - En-têtes de 12 octets
- 0 octets de remplissage
Taille maximale du tableau < Integer.MAX_VALUE
Non, votre maximum est incorrect.
La limite du nombre d'éléments dans un tableau en Java est un peu inférieure à Integer.MAX_VALUE(2 147 483 647), selon la version de Java, le système d'exploitation hôte et la manière dont Java a été compilé. Voir cette réponse d'Ivan Mamontov sur la question, pourquoi je ne peux pas créer un tableau de grande taille? .
Oui, le plus grand choix de int
8 concerts
Ainsi, la taille d'un tableau maximal de int
sera approximativement de ( Integer.MAX_VALUE - 8L ) * 32L
bits, soit 68 719 476 448 bits, soit 8 589 934 556 octets.
Alors oui, environ 8 Go de mémoire. Et rappelez-vous: il s'agit de la mémoire contiguë pour un tableau. Donc:
- Il peut y avoir un travail important de la part de la JVM et du système d'exploitation hôte pour produire un tel tableau en fonction de la fragmentation de la mémoire à ce moment pendant l'exécution.
- Si le matériel hôte ne dispose pas de suffisamment de mémoire réelle, vous vous retrouverez dans la mémoire virtuelle où la pagination qui en résulte peut entraîner des performances terribles.
Faites toujours des tests dans le monde réel si vous repoussez vraiment ces limites dans votre travail. Et vous voudrez peut-être envisager des implémentations alternatives de Java conçues pour une très grande mémoire, telles que Zing by Azul Systems.