Platzbedarf, um das größte Integer-Array im Speicher zu halten

Jan 04 2021

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

3 Eugene Jan 05 2021 at 01:39

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ühren

  • 4 Bytes, um lengthdas Array zu behalten

  • Polsterung.

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. Integerist ein Objekt, sodass Sie eine Referenz innerhalb des Arrays speichern (die je nach Flag 4oder 8Bytes sein kann UseCompressedOops), und für jede IntegerInstanz sind 2 Header erforderlich (jede Integerist 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 UseCompressedOopeingeschaltet), 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 intsie enthalten
  • 12-Byte-Header
  • 0 Bytes Auffüllen
1 BasilBourque Jan 04 2021 at 15:23

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 intalso ungefähr ( Integer.MAX_VALUE - 8L ) * 32LBits, 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.