Espaço necessário para manter a maior matriz de inteiros na memória

Jan 04 2021

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

3 Eugene Jan 05 2021 at 01:39

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á executando

  • 4 bytes para manter o lengthda matriz

  • preenchimento.

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 4ou 8bytes, dependendo do UseCompressedOopssinalizador), mais cada uma das Integerinstâncias exigirá 2 cabeçalhos (cada Integerum é 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 UseCompressedOopliguei), 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 intque eles mantêm
  • Cabeçalhos de 12 bytes
  • Preenchimento de 0 bytes
1 BasilBourque Jan 04 2021 at 15:23

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 intserá de aproximadamente ( Integer.MAX_VALUE - 8L ) * 32Lbits, 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.