As matrizes Java têm um tamanho máximo?

214

Existe um limite para o número de elementos que uma matriz Java pode conter? Se assim for, o que é?

Lagarto
fonte
5
Você aceitou uma resposta errada, tente alocar uma matriz tão longa (e não, não estou ficando sem memória).
maaartinus 28/09/12
Intimamente relacionados: stackoverflow.com/questions/878309/…
Ciro Santilli escreveu:
A resposta certa é stackoverflow.com/questions/31382531/…
Ivan Mamontov

Respostas:

184

Não vi a resposta certa, mesmo que seja muito fácil de testar.

Em uma VM HotSpot recente, a resposta correta é Integer.MAX_VALUE - 5. Depois de ir além disso:

public class Foo {
  public static void main(String[] args) {
    Object[] array = new Object[Integer.MAX_VALUE - 4];
  }
}

Você obtém:

Exception in thread "main" java.lang.OutOfMemoryError:
  Requested array size exceeds VM limit
Kevin Bourrillion
fonte
57
Penso que a ideia de voto negativo não faz sentido, a menos que estejamos dispostos a votar de forma clara e simplesmente errada . A diferença de cinco bytes realmente importa no mundo real, NÃO, claro que não. Mas me preocupa que as pessoas estejam dispostas a dar uma resposta "autoritariamente" sem sequer tentar ver se realmente funciona. Quanto ao limite de memória, bem, DUH. É como se você me perguntasse "quantas uvas você pode comer?" e eu disse "bem, depende de quantos eu tenho na geladeira no momento".
Kevin Bourrillion
7
Você sabe por que não lhe dará esses cinco bytes? Isso é necessariamente algo que sempre acontece em Java, ou poderia estar relacionado à memória do computador ou algo assim?
Taymon
17
@ Kevin Bourrillion: Isso parece ter mudado, usando o Oracle 1.7.0_07 eu posso alocar até MAX_VALUE-2elementos. Isso é independente do que eu aloco, e realmente me pergunto para que a VM pode usar as duas "coisas" (o comprimento não cabe em 2 bytes).
maaartinus
3
@ TomášZato o mais tardar em Integer.MAX_VALUE+1, você terá um número inteiro excedente. Os tamanhos de matriz em Java intnão são long; independentemente do tipo de dados que você armazena em sua matriz, bytes ou referências. Strings são apenas referências a objetos.
Saiu - Anony-Mousse 5/05
8
O número máximo de elementos em uma matriz no JDK 6 e acima é Integer.MAX_VALUE - 2= 2 147 483 645. O Java aloca com êxito essa matriz se você a executar -Xmx13G. Falha com OutOfMemoryError: Java heap spacese você passar -Xmx12G.
Alexey Ivanov
127

Isso (é claro) é totalmente dependente da VM.

Navegando através do código-fonte do OpenJDK 7 e 8 java.util.ArrayList, .Hashtable, .AbstractCollection, .PriorityQueue, e .Vector, você pode ver esta reivindicação ser repetido:

/**
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

adicionado por Martin Buchholz (Google) em 09/05/2010 ; revisado por Chris Hegarty (Oracle).

Portanto, provavelmente podemos dizer que o número "seguro" máximo seria 2 147 483 639 ( Integer.MAX_VALUE - 8) e "tentativas de alocar matrizes maiores podem resultar em OutOfMemoryError ".

(Sim, a reivindicação autônoma de Buchholz não inclui evidências de apoio, portanto esse é um apelo calculado à autoridade. Mesmo dentro do próprio OpenJDK, podemos ver código como o return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;que mostra que MAX_ARRAY_SIZEainda não tem uso real .)

Pacerier
fonte
E por que precisamos adicionar -8?
31715 JohnWinter
@Pacerier. Este MAX_ARRAY_SIZE não deve ser aplicado apenas quando você estiver usando um ArrayList? Isso é diferente de usar uma matriz como int [] array = new int [some_value_here]; não é? Por que uma constante definida em ArrayList pode ser aplicada a uma matriz normal (definida com [])? Eles são os mesmos nos bastidores?
Tiago
1
@ Tiago, Não, o código em si não tem nada a ver com o tamanho máximo de matrizes. É apenas uma reivindicação.
Pacerier
@JohnWinter, A citação declara "Algumas VMs reservam algumas palavras de cabeçalho em uma matriz". Portanto, isso -8ocorre devido aos bytes que as palavras reservadas do cabeçalho ocupariam.
Pacerier
38

Na verdade, existem dois limites. Um, o elemento máximo indexável para a matriz e, dois, a quantidade de memória disponível para seu aplicativo. Dependendo da quantidade de memória disponível e da quantidade usada por outras estruturas de dados, você pode atingir o limite de memória antes de atingir o elemento máximo da matriz endereçável.

tvanfosson
fonte
27

Indo por este artigo http://en.wikipedia.org/wiki/Criticism_of_Java#Large_arrays :

Java tem sido criticada por não apoiar matrizes de mais de 2 31 -1 (cerca de 2,1 mil milhões) elementos. Esta é uma limitação do idioma; a Especificação de Linguagem Java, Seção 10.4, afirma que:

As matrizes devem ser indexadas pelos valores int ... Uma tentativa de acessar um componente da matriz com um valor de índice longo resulta em um erro em tempo de compilação.

O suporte a matrizes grandes também exigiria alterações na JVM. Essa limitação se manifesta em áreas como coleções limitadas a 2 bilhões de elementos e incapacidade de armazenar arquivos de mapas com memória maior que 2 GiB. O Java também não possui matrizes multidimensionais verdadeiras (blocos únicos de memória alocados de forma contígua acessados ​​por um único indireto), o que limita o desempenho da computação científica e técnica.

trabalhando
fonte
6
Java não tem o açúcar sintático para arrays multidimensionais, mas você ainda pode "ter"-los com um pouco de multiplicação (a menos que o tamanho total da matriz excedeu o limite citado anteriormente)
kbolino
11

As matrizes são um número inteiro não negativo indexado; portanto, o tamanho máximo da matriz que você pode acessar seria Integer.MAX_VALUE. A outra coisa é o tamanho da matriz que você pode criar. Depende da memória máxima disponível para o seu JVMe o tipo de conteúdo da matriz. Cada elemento da matriz possui seu tamanho, exemplo. byte = 1 byte, int = 4 bytes,Object reference = 4 bytes (on a 32 bit system)

Portanto, se você tiver 1 MBmemória disponível em sua máquina, poderá alocar uma matriz de byte[1024 * 1024]ou Object[256 * 1024].

Respondendo à sua pergunta - Você pode alocar uma matriz de tamanho (memória / tamanho máximo disponível do item da matriz).

Resumo - Teoricamente, o tamanho máximo de uma matriz será Integer.MAX_VALUE. Praticamente, depende de quanta memória você JVMpossui e de quanto já foi alocado para outros objetos.

Dhanuka
fonte
3

Eu tentei criar uma matriz de bytes como esta

byte[] bytes = new byte[Integer.MAX_VALUE-x];
System.out.println(bytes.length);

Com esta configuração de execução:

-Xms4G -Xmx4G

E versão java:

Versão do Openjdk "1.8.0_141"

OpenJDK Runtime Environment (compilação 1.8.0_141-b16)

VM do servidor OpenJDK de 64 bits (compilação 25.141-b16, modo misto)

Funciona apenas para x> = 2, o que significa que o tamanho máximo de uma matriz é Inteiro.MAX_VALUE-2

Valores acima que dão

Exceção no encadeamento "main" java.lang.OutOfMemoryError: o tamanho da matriz solicitada excede o limite da VM em Main.main (Main.java:6)

Vasilis Nicolaou
fonte
2

Sim, há limite na matriz java. Java usa um número inteiro como um índice para a matriz e o armazenamento inteiro máximo da JVM é 2 ^ 32. para que você possa armazenar 2.147.483.647 elementos na matriz.

Caso precise de mais do que o tamanho máximo, você pode usar duas matrizes diferentes, mas o método recomendado é armazenar dados em um arquivo. porque armazenar dados no arquivo não tem limite. porque os arquivos são armazenados nos drivers de armazenamento, mas a matriz é armazenada na JVM. A JVM fornece espaço limitado para a execução do programa.

Avinash Barde
fonte
1

Número máximo de elementos de um arrayé (2^31)−1ou2 147 483 647

bebê
fonte
5
Java não pode alocar matriz de tamanho Integer.MAX_VALUE - 1, você receberá "java.lang.OutOfMemoryError: o tamanho da matriz solicitada excede o limite da VM". O número máximo de elementos no JDK 6 e acima é Integer.MAX_VALUE - 2= 2 147 483 645. #
Alexey Ivanov
0

Na verdade, é a limitação de java que o limita em 2 ^ 30-4, sendo 1073741820. Não em 2 ^ 31-1. Não sei por que, mas eu testei manualmente no jdk. 2 ^ 30-3 ainda jogando vm, exceto

Edit: corrigido de -1 a -4, verificado no windows jvm

Ferned
fonte
Você está usando uma JVM de 32 bits. Use uma JVM de 64 bits e o limite da JVM será próximo de 2 ^ 31. (Você também precisa de espaço de pilha disponível, o que não é o padrão, e vai ser afectada pela sua memória física.)
dave_thompson_085