Espaço necessário para manter a maior matriz de inteiros na memória
Estou revisando um algoritmo e ele mantém uma matriz de inteiros, o tamanho da entrada é dinâmico. Portanto, de acordo com meus cálculos, pode demorar até
integer MAX_VALUE * int size = ?
2^31 integers * 4 bytes = ?
2147483648 integers * 4 bytes = 8 Gigabytes
Este cálculo está correto? a JVM usaria tanto espaço contíguo para armazenar o array int ou há outras coisas que é preciso considerar?
Respostas
O tamanho teórico da matriz seria:
numberOfElementsInTheArray * 4 bytes
12 bytes de cabeçalhos (
int[]
é um objeto). Na verdade, o tamanho dos cabeçalhos depende dos sinalizadores que você usou e da versão JVM que você está executando4 bytes para manter o
length
da matrizpreenchimento.
Por exemplo: (vou usar o JOL para isso ):
int [] x = new int[10];
for(int i=0;i<10;++i){
x[i] = 9999;
}
System.out.println(GraphLayout.parseInstance((Object)x).toPrintable());
irá produzir:
[I@7a81197dd object externals:
ADDRESS SIZE TYPE PATH VALUE
70fe45268 56 [I [9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999, 9999]
Então tem 56 bytes
:
- 40 para os próprios valores (10 ints * 4 bytes)
- 12 para cabeçalhos
- 4 para comprimento
- 0 para preenchimento
Se você alterar esse array para Integer
, as coisas mudam dramaticamente. Integer
é um objeto, portanto, você armazenará uma referência dentro do array (que pode ser 4
ou 8
bytes, dependendo do UseCompressedOops
sinalizador), mais cada uma das Integer
instâncias exigirá 2 cabeçalhos (cada Integer
um é um 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 irá 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)
Um total de 216 bytes
:
- 4 bytes para cada referência (eu
UseCompressedOop
liguei), 40 bytes no total - Cabeçalhos de 12 bytes da matriz
- 4 bytes de comprimento da matriz
- Preenchimento de 0 bytes
Cada referência dessa matriz aponta para um Integer
, cada um desses objetos terá 16 bytes
:
- 4 bytes para o interior
int
que eles mantêm - Cabeçalhos de 12 bytes
- Preenchimento de 0 bytes
Tamanho máximo da matriz < Integer.MAX_VALUE
Não, seu máximo está incorreto.
O limite do número de elementos em um array em Java é um pouco menor que Integer.MAX_VALUE(2.147.483.647), dependendo da versão do Java, do sistema operacional do host e de como o Java foi compilado. Veja esta resposta de Ivan Mamontov na pergunta: Por que não consigo criar um array com tamanho grande? .
Sim, maior variedade de int
≈ 8 shows
Portanto, o tamanho de uma matriz máxima de int
será de aproximadamente ( Integer.MAX_VALUE - 8L ) * 32L
bits, que é 68.719.476.448 bits, que é 8.589.934.556 octetos.
Então, sim, cerca de 8 GB de memória. E lembre-se: esta é uma memória contígua para um array. Então:
- Pode haver um trabalho significativo por parte da JVM e do SO host para produzir tal array, dependendo de quão fragmentada está a memória naquele momento durante o tempo de execução.
- Se o hardware do host não tiver memória real suficiente, você entrará na memória virtual, onde a paginação resultante pode levar a um desempenho terrível.
Sempre faça testes do mundo real se você realmente está ultrapassando esses limites em seu trabalho. E você pode querer considerar implementações alternativas de Java projetadas para memória muito grande, como Zing da Azul Systems.