Spazio richiesto per mantenere la matrice di numeri interi più grande in memoria

Jan 04 2021

Sto rivedendo un algoritmo e mantiene un array di numeri interi, la dimensione dell'input è dinamica. Quindi secondo i miei calcoli può richiedere tanto quanto

  integer MAX_VALUE  * int size  = ?   
      2^31 integers  * 4 bytes   = ?
2147483648 integers  * 4 bytes   = 8 Gigabytes

Questo calcolo è corretto? la JVM utilizzerebbe questo spazio contiguo per memorizzare l'array int o ci sono altre cose che è necessario considerare?

Risposte

3 Eugene Jan 05 2021 at 01:39

La dimensione teorica dell'array sarebbe:

  • numberOfElementsInTheArray * 4 byte

  • 12 byte di intestazioni ( int[]è un oggetto). In realtà la dimensione delle intestazioni dipende dai flag che hai usato e dalla versione JVM che stai eseguendo

  • 4 byte per mantenere lengthil valore dell'array

  • imbottitura.

Ad esempio: (userò JOL per questo ):

    int [] x = new int[10];
    for(int i=0;i<10;++i){
        x[i] = 9999;
    }
    System.out.println(GraphLayout.parseInstance((Object)x).toPrintable()); 

produrrà:

 [I@7a81197dd object externals:
      ADDRESS       SIZE TYPE PATH                           VALUE
    70fe45268         56 [I                                  [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999]

Quindi ha 56 bytes:

  • 40 per i valori stessi (10 int * 4 byte)
  • 12 per le intestazioni
  • 4 per la lunghezza
  • 0 per imbottitura

Se si modifica questo array in Integer, le cose cambiano drasticamente. Integerè un oggetto, quindi memorizzerai un riferimento all'interno dell'array (che potrebbe essere 4o 8byte, a seconda del UseCompressedOopsflag), più ciascuna delle Integeristanze richiederà 2 intestazioni (ciascuna Integerè un oggetto).

    Integer[] y = new Integer[10];
    for(int i=0;i<10;++i){
        y[i] = 9999;
    }

    System.out.println(GraphLayout.parseInstance((Object)y).toFootprint());

che mostrerà:

   [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 totale di 216 bytes:

  • 4 byte per ogni riferimento (ho UseCompressedOopacceso), 40 byte totali
  • 12 byte di intestazioni dell'array
  • 4 byte di lunghezza dell'array
  • 0 byte di riempimento

Ogni riferimento da quell'array punta a un Integer, ciascuno di quegli Oggetti avrà 16 bytes:

  • 4 byte per l'interno intche tengono
  • 12 byte di intestazioni
  • 0 byte di riempimento
1 BasilBourque Jan 04 2021 at 15:23

Dimensione matrice massima < Integer.MAX_VALUE

No, il tuo massimo non è corretto.

Il limite al numero di elementi in un array in Java è leggermente inferiore a Integer.MAX_VALUE(2.147.483.647), a seconda della versione di Java, del sistema operativo host e del modo in cui Java è stato compilato. Vedi questa risposta di Ivan Mamontov alla domanda, perché non riesco a creare un array di grandi dimensioni? .

Sì, la più vasta gamma di int≈ 8 concerti

Quindi la dimensione di un array massimo di intsarà approssimativamente ( Integer.MAX_VALUE - 8L ) * 32Lbit che è 68.719.476.448 bit che è 8.589.934.556 ottetti.

Quindi sì, circa 8 giga di memoria. E ricorda: questa è memoria contigua per un array. Così:

  • Potrebbe esserci un lavoro significativo da parte della JVM e del sistema operativo host per produrre un array di questo tipo, a seconda di quanto è frammentata la memoria in quel momento durante il runtime.
  • Se l'hardware host non dispone di memoria reale sufficiente, entrerai nella memoria virtuale in cui il paging risultante potrebbe portare a prestazioni terribili.

Fai sempre test nel mondo reale se stai davvero spingendo questi limiti nel tuo lavoro. E potresti prendere in considerazione implementazioni alternative di Java progettate per una memoria molto grande, come Zing di Azul Systems.