Espacio requerido para mantener la matriz de enteros más grande en la memoria
Estoy revisando un algoritmo y mantiene una matriz de números enteros, el tamaño de la entrada es dinámico. Entonces, según mis cálculos, puede tomar tanto como
integer MAX_VALUE * int size = ?
2^31 integers * 4 bytes = ?
2147483648 integers * 4 bytes = 8 Gigabytes
¿Es correcto este cálculo? ¿Usaría la JVM este espacio contiguo para almacenar la matriz int o hay otras cosas que se deben considerar?
Respuestas
El tamaño teórico de la matriz sería:
numberOfElementsInTheArray * 4 bytes
12 bytes de encabezados (
int[]
es un objeto). En realidad, el tamaño de los encabezados depende de los indicadores que utilizó y de la versión de JVM que esté ejecutando.4 bytes para mantener el
length
de la matrizrelleno.
Por ejemplo: (voy a usar JOL para esto ):
int [] x = new int[10];
for(int i=0;i<10;++i){
x[i] = 9999;
}
System.out.println(GraphLayout.parseInstance((Object)x).toPrintable());
dará salida:
[I@7a81197dd object externals:
ADDRESS SIZE TYPE PATH VALUE
70fe45268 56 [I [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999]
Entonces tiene 56 bytes
:
- 40 para los valores mismos (10 pulgadas * 4 bytes)
- 12 para encabezados
- 4 de longitud
- 0 para relleno
Si cambia esta matriz a Integer
, las cosas cambian drásticamente. Integer
es un Objeto, por lo que almacenará una referencia dentro de la matriz (que podría ser 4
o 8
bytes, dependiendo de la UseCompressedOops
bandera), además cada una de las Integer
instancias requerirá 2 encabezados (cada uno Integer
es un Objeto).
Integer[] y = new Integer[10];
for(int i=0;i<10;++i){
y[i] = 9999;
}
System.out.println(GraphLayout.parseInstance((Object)y).toFootprint());
que mostrará:
[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 bytes para cada referencia (lo he
UseCompressedOop
encendido), 40 bytes en total - 12 bytes de encabezados de la matriz
- 4 bytes de longitud de la matriz
- Relleno de 0 bytes
Cada referencia de esa matriz apunta a un Integer
, cada uno de esos Objetos tendrá 16 bytes
:
- 4 bytes para el interior
int
que contienen - Encabezados de 12 bytes
- Relleno de 0 bytes
Tamaño de matriz máximo < Integer.MAX_VALUE
No, tu máximo es incorrecto.
El límite en la cantidad de elementos en una matriz en Java es un poco menor que Integer.MAX_VALUE(2,147,483,647), dependiendo de la versión de Java, el sistema operativo host y cómo se compiló Java. Vea esta respuesta de Ivan Mamontov sobre la pregunta, ¿Por qué no puedo crear una matriz de gran tamaño? .
Sí, la mayor variedad de int
≈ 8 conciertos
Entonces, el tamaño de una matriz máxima int
será aproximadamente de ( Integer.MAX_VALUE - 8L ) * 32L
bits, que es de 68,719,476,448 bits, que es de 8,589,934,556 octetos.
Entonces sí, alrededor de 8 gigas de memoria. Y recuerde: esta es la memoria contigua para una matriz. Entonces:
- Puede haber un trabajo significativo por parte de la JVM y el sistema operativo host para producir una matriz de este tipo, dependiendo de qué tan fragmentada esté la memoria en ese momento durante el tiempo de ejecución.
- Si el hardware del host no tiene suficiente memoria real, estará pasando a la memoria virtual donde la paginación resultante puede conducir a un rendimiento terrible.
Siempre haga pruebas del mundo real si realmente está superando estos límites en su trabajo. Y es posible que desee considerar implementaciones alternativas de Java diseñadas para una memoria muy grande, como Zing de Azul Systems.