¿Se almacena una matriz Java de primitivas en pila o montón?

85

Tengo una declaración de matriz como esta:

int a[];

Aquí ahay una matriz de inttipo primitivo . ¿Dónde se almacena esta matriz? ¿Se almacena en un montón o en una pila? Este es un tipo intprimitivo, todos los tipos primitivos no se almacenan en el montón.

user241924
fuente
38
Eso no es una matriz. Es una referencia a una matriz. La referencia en sí misma podría almacenarse en el montón si es miembro de una clase u objeto, o en la pila si es una variable local en un método. Y los tipos primitivos se pueden almacenar en el montón si son miembros de una clase u objeto.
tío O

Respuestas:

143

Como dijo gurukulki, se almacena en el montón. Sin embargo, su publicación sugirió un malentendido probablemente debido a que alguna persona bien intencionada propagó el mito de que "los primitivos siempre viven en la pila". Esto es falso. Las variables locales tienen sus valores en la pila, pero no todas las variables primitivas son locales ...

Por ejemplo, considere esto:

public class Foo
{
    int value;
}
...

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

Ahora bien, ¿dónde f.valuevive? El mito sugeriría que está en la pila, pero en realidad es parte del nuevo Fooobjeto y vive en el montón 1 . (Tenga en cuenta que el valor de fsí mismo es una referencia y vive en la pila).

A partir de ahí, es un paso fácil para las matrices. Puede pensar en una matriz como si fueran muchas variables, por lo que new int[3]es un poco como tener una clase de esta forma:

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

1 De hecho, es más complicado que esto. La distinción pila / montón es principalmente un detalle de implementación; creo que algunas JVM, posiblemente experimentales, pueden decir cuándo un objeto nunca "escapa" de un método y pueden asignar todo el objeto a la pila. Sin embargo, está conceptualmente en el montón, si decide preocuparse.

Jon Skeet
fuente
1
Acerca del "análisis de escape" en Java: blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead Dice que está presente desde la versión de acceso temprano de JDK 6 Update 14, y habilitado de forma predeterminada desde la actualización 23 de JDK 6.
Guido
¿Cambia algo si la matriz es pública estática final? Entonces, ¿no debería ser parte del grupo constante?
Malachiasz
@Malachiasz: No. Una matriz nunca es una constante.
Jon Skeet
@JonSkeet: En todas las versiones de la biblioteca de Java que conozco, todas Stringestán respaldadas por un char[]. Creo que las cadenas literales se almacenan en el grupo público constante; para la optimización de GC, eso implicaría que las matrices de respaldo deberían almacenarse de la misma manera (de lo contrario, el grupo constante tendría que escanearse durante cualquier ciclo de GC en el que la matriz de respaldo sería elegible para la recolección).
supercat
@supercat: Sí, eso tendría sentido. Pero cualquier matriz que usted mismo declare nunca termina como parte del grupo constante.
Jon Skeet
37

Se almacenará en el montón

porque array es un objeto en java.

EDITAR : si tienes

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

Piense en este código como si le dijera al compilador: "Cree un objeto de matriz que tenga cuatro entradas y asígnelo a la variable de referencia nombrada testScores. Además, siga adelante y establezca cada intelemento en cero. Gracias".

GuruKulki
fuente
2
Y la variable de referencia llamada testScores (apuntando a la matriz en el montón) estará en la pila.
Zaki
11
El código solo dice "Gracias" si proporciona la -gopción al compilador. De lo contrario, se optimizará.
mob
1
@mob Está asumiendo que este es el único código. Probablemente sea mejor asumir que estas dos líneas son parte de un programa más grande que realmente usa la matriz.
Code-Apprentice
22

Es una serie de tipos primitivos que en sí mismos no son primitivos. Una buena regla general es que cuando la nueva palabra clave está involucrada, el resultado estará en el montón.

Esben Skov Pedersen
fuente
18

Solo quería compartir algunas pruebas que hice sobre este tema.

Matriz de tamaño 10 millones

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

Salida:

------------------------
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 puede ver, el tamaño del montón usado aumenta en ~ 80 MB, que es 10 m * tamaño de (doble).

Pero si usamos Double en lugar de double

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

La salida mostrará 40 MB. Solo tenemos referencias dobles, no están inicializadas.

Llenarlo con 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();
}

Todavía 40 MB. Porque todos apuntan al mismo objeto Double.

Inicializando con doble en su lugar

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

Línea

a[i] = qq.doubleValue();

es equivalente a

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

que es equivalente a

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

Como creamos nuevos objetos Double cada vez, explotamos el montón. Esto muestra que los valores dentro de la clase Double se almacenan en el montón.

acheron55
fuente
1
¿Podría pegar el detalle del código de memInfo () por favor? :)
hedleyyan