Uma matriz Java de primitivos é armazenada em pilha ou heap?

85

Eu tenho uma declaração de matriz como esta:

int a[];

Aqui aestá uma matriz de inttipo primitivo . Onde esta matriz está armazenada? É armazenado em heap ou pilha? Este é um tipo intprimitivo, todos os tipos primitivos não são armazenados no heap.

user241924
fonte
38
Isso não é uma matriz. É uma referência a um array. A própria referência pode ser armazenada no heap se for um membro de uma classe ou objeto, ou na pilha se for uma variável local em um método. E os tipos primitivos podem ser armazenados no heap se forem membros de uma classe ou objeto.
tioO de

Respostas:

145

Como disse o gurukulki, ele é armazenado na pilha. Porém, sua postagem sugeriu um mal-entendido provavelmente devido a alguma pessoa bem-intencionada propagando o mito de que "os primitivos sempre vivem na pilha". Isso não é verdade. Variáveis ​​locais têm seus valores na pilha, mas nem todas as variáveis ​​primitivas são locais ...

Por exemplo, considere o seguinte:

public class Foo
{
    int value;
}
...

public void someOtherMethod()
{
    Foo f = new Foo();
    ...
}

Agora, onde f.valuemora? O mito sugere que está na pilha - mas, na verdade, é parte do novo Fooobjeto e vive na pilha 1 . (Observe que o valor em fsi é uma referência e permanece na pilha.)

A partir daí, é uma etapa fácil para os arrays. Você pode pensar em um array apenas como um monte de variáveis ​​- então new int[3]é um pouco como ter uma classe desta forma:

public class ArrayInt3
{
    public readonly int length = 3;
    public int value0;
    public int value1;
    public int value2;
}

1 Na verdade, é mais complicado do que isso. A distinção pilha / heap é principalmente um detalhe de implementação - acredito que algumas JVMs, possivelmente experimentais, podem dizer quando um objeto nunca "escapa" de um método e podem alocar o objeto inteiro na pilha. No entanto, está conceitualmente na pilha, se você decidir se importar.

Jon Skeet
fonte
1
Sobre o "escape analyisis" em Java: blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead Diz que está presente desde o lançamento de acesso antecipado do JDK 6 Atualização 14, e habilitado por padrão desde JDK 6 Atualização 23.
Guido
isso muda alguma coisa se o array for public static final? Não deveria fazer parte da piscina constante, então?
Malachiasz
@Malachiasz: Não. Uma matriz nunca é uma constante.
Jon Skeet
@JonSkeet: Em todas as versões da biblioteca Java que conheço, todas Stringsão apoiadas por um char[]. Eu acredito que strings literais são armazenadas no pool de constantes públicas; para a otimização de GC, isso implicaria que as matrizes de apoio deveriam ser armazenadas da mesma forma (caso contrário, o pool constante teria que ser verificado durante qualquer ciclo de GC onde a matriz de apoio seria elegível para coleta).
supercat
@supercat: Sim, faria sentido. Mas qualquer matriz você declarar -se não acaba como parte do pool constante.
Jon Skeet
37

Ele será armazenado na pilha

porque array é um objeto em java.

EDITAR : se você tiver

int [] testScores; 
testScores = new int[4];

Pense neste código como se estivesse dizendo ao compilador: "Crie um objeto de matriz que conterá quatro ints e atribua-o à variável de referência chamada testScores . Além disso, vá em frente e defina cada intelemento como zero. Obrigado."

GuruKulki
fonte
3
E a variável de referência chamada testScores (apontando para a matriz no heap) estará na pilha.
Zaki
11
O código apenas diz "Obrigado" se você fornecer a -gopção ao compilador. Caso contrário, ele será otimizado.
mob
1
@mob Você está supondo que este é o único código. Provavelmente, é melhor assumir que essas duas linhas são parte de um programa maior que realmente usa o array.
Code-Apprentice
22

É uma série de tipos primitivos que em si não são primitivos. Uma boa regra prática é que, quando a nova palavra-chave estiver envolvida, o resultado ficará na pilha.

Esben Skov Pedersen
fonte
19

Eu só queria compartilhar alguns testes que fiz sobre esse assunto.

Matriz de tamanho 10 milhões

public static void main(String[] args) {
    memInfo();
    double a[] = new double[10000000];
    memInfo();
}

Resultado:

------------------------
max mem = 130.0 MB
total mem = 85.0 MB
free mem = 83.6 MB
used mem = 1.4 MB
------------------------
------------------------
max mem = 130.0 MB
total mem = 130.0 MB
free mem = 48.9 MB
used mem = 81.1 MB
------------------------

Como você pode ver, o tamanho do heap usado foi aumentado em ~ 80 MB, que é 10m * sizeof (double).

Mas se tivermos de usar Double em vez de double

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    memInfo();
}

A saída mostrará 40 MB. Temos apenas referências duplas, elas não são inicializadas.

Preenchendo com Double

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];      
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq;
    }
    memInfo();
}

Ainda com 40 MB. Porque todos eles apontam para o mesmo objeto Duplo.

Inicializando com double ao invés

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq.doubleValue();
    }
    memInfo();
}

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Linha

a[i] = qq.doubleValue();

é equivalente a

a[i] = Double.valueOf(qq.doubleValue());

que é equivalente a

a[i] = new Double(qq.doubleValue());

Como criamos novos objetos Double a cada vez, explodimos o heap. Isso mostra que os valores dentro da classe Double são armazenados no heap.

acheron55
fonte
1
Você poderia colar o detalhe do código de memInfo () pls? :)
hedleyyan