Platzbedarf, um das größte Integer-Array im Speicher zu halten
Ich überprüfe einen Algorithmus und er behält ein Array von ganzen Zahlen bei. Die Größe der Eingabe ist dynamisch. Nach meinen Berechnungen kann es also so viel dauern wie
integer MAX_VALUE * int size = ?
2^31 integers * 4 bytes = ?
2147483648 integers * 4 bytes = 8 Gigabytes
Ist diese Berechnung korrekt? Würde die JVM diesen zusammenhängenden Speicherplatz zum Speichern des int-Arrays verwenden, oder gibt es andere Dinge, die berücksichtigt werden müssen?
Antworten
Die theoretische Größe des Arrays wäre:
numberOfElementsInTheArray * 4 Bytes
12 Byte Header (
int[]
ist ein Objekt). Tatsächlich hängt die Größe der Header von den verwendeten Flags und der JVM-Version ab, die Sie ausführen4 Bytes, um
length
das Array zu behaltenPolsterung.
Zum Beispiel: (Ich werde dafür JOL verwenden ):
int [] x = new int[10];
for(int i=0;i<10;++i){
x[i] = 9999;
}
System.out.println(GraphLayout.parseInstance((Object)x).toPrintable());
wird ausgegeben:
[I@7a81197dd object externals:
ADDRESS SIZE TYPE PATH VALUE
70fe45268 56 [I [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999]
So hat es 56 bytes
:
- 40 für die Werte selbst (10 Zoll * 4 Byte)
- 12 für Überschriften
- 4 für die Länge
- 0 zum Auffüllen
Wenn Sie dieses Array in Integer
ändern, ändern sich die Dinge dramatisch. Integer
ist ein Objekt, sodass Sie eine Referenz innerhalb des Arrays speichern (die je nach Flag 4
oder 8
Bytes sein kann UseCompressedOops
), und für jede Integer
Instanz sind 2 Header erforderlich (jede Integer
ist ein Objekt).
Integer[] y = new Integer[10];
for(int i=0;i<10;++i){
y[i] = 9999;
}
System.out.println(GraphLayout.parseInstance((Object)y).toFootprint());
was zeigen wird:
[Ljava.lang.Integer;@369f73a2d footprint:
COUNT AVG SUM DESCRIPTION
1 56 56 [Ljava.lang.Integer;
10 16 160 java.lang.Integer
11 216 (total)
Insgesamt 216 bytes
:
- 4 Bytes für jede Referenz (ich habe
UseCompressedOop
eingeschaltet), insgesamt 40 Bytes - 12-Byte-Header des Arrays
- 4 Bytes Länge des Arrays
- 0 Bytes Auffüllen
Jede Referenz von diesem Array zeigt auf ein Integer
, jedes dieser Objekte hat 16 bytes
:
- 4 Bytes für das Innere, das
int
sie enthalten - 12-Byte-Header
- 0 Bytes Auffüllen
Arraygröße maximal < Integer.MAX_VALUE
Nein, dein Maximum ist falsch.
Die Begrenzung der Anzahl der Elemente in einem Array in Java liegt etwas unter Integer.MAX_VALUE(2.147.483.647), abhängig von der Java-Version, dem Host-Betriebssystem und der Art und Weise, wie Java kompiliert wurde. Siehe diese Antwort von Ivan Mamontov zur Frage, warum ich kein Array mit großer Größe erstellen kann. .
Ja, die größte Auswahl an int
≈ 8 Gigs
Die Größe eines maximalen Arrays von beträgt int
also ungefähr ( Integer.MAX_VALUE - 8L ) * 32L
Bits, was 68.719.476.448 Bits entspricht, was 8.589.934.556 Oktetten entspricht.
Also ja, ungefähr 8 Gigs Speicher. Und denken Sie daran: Dies ist ein zusammenhängender Speicher für ein Array. So:
- Die JVM und das Host-Betriebssystem müssen möglicherweise erhebliche Anstrengungen unternehmen, um ein solches Array zu erstellen, je nachdem, wie fragmentiert der Speicher zu diesem Zeitpunkt zur Laufzeit ist.
- Wenn die Host-Hardware nicht über genügend realen Speicher verfügt, verfallen Sie in den virtuellen Speicher, wo das resultierende Paging zu einer schrecklichen Leistung führen kann.
Führen Sie immer Tests in der Praxis durch, wenn Sie diese Grenzen bei Ihrer Arbeit wirklich überschreiten. Möglicherweise möchten Sie alternative Implementierungen von Java in Betracht ziehen, die für sehr großen Speicher ausgelegt sind, z. B. Zing von Azul Systems.