Spazio richiesto per mantenere la matrice di numeri interi più grande in memoria
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
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 eseguendo4 byte per mantenere
length
il valore dell'arrayimbottitura.
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 4
o 8
byte, a seconda del UseCompressedOops
flag), più ciascuna delle Integer
istanze 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
UseCompressedOop
acceso), 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
int
che tengono - 12 byte di intestazioni
- 0 byte di riempimento
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 int
sarà approssimativamente ( Integer.MAX_VALUE - 8L ) * 32L
bit 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.