Un array Java di primitive è memorizzato nello stack o nell'heap?


85

Ho una dichiarazione di array come questa:

int a[];

Ecco aun array di inttipo primitivo . Dove è archiviato questo array? È archiviato nell'heap o nello stack? Questo è un tipo intprimitivo, tutti i tipi primitivi non sono archiviati nell'heap.


38
Questo non è un array. È un riferimento a un array. Il riferimento stesso potrebbe essere memorizzato nell'heap se è un membro di una classe o di un oggetto, o nello stack se è una variabile locale in un metodo. E i tipi primitivi possono essere archiviati nell'heap se sono membri di una classe o di un oggetto.
zioO

Risposte:


145

Come ha detto Gurukulki, è immagazzinato nel mucchio. Tuttavia, il tuo post ha suggerito un malinteso probabilmente dovuto a una persona ben intenzionata che diffonde il mito che "le primitive vivono sempre in pila". Questo non è vero. Le variabili locali hanno i loro valori in pila, ma non tutte le variabili primitive sono locali ...

Ad esempio, considera questo:

public class Foo
{
    int value;
}
...

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

Allora, dove f.valueabita? Il mito suggerirebbe che sia in pila, ma in realtà fa parte del nuovo Foooggetto e vive nel mucchio 1 . (Nota che il valore di fse stesso è un riferimento e vive nello stack.)

Da lì, il passaggio agli array è semplice. Puoi pensare a un array come a molte variabili, quindi new int[3]è un po 'come avere una classe di questa forma:

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

1 In effetti, è più complicato di così. La distinzione stack / heap è principalmente un dettaglio di implementazione - credo che alcune JVM, possibilmente sperimentali, possano dire quando un oggetto non "sfugge" mai da un metodo e possono allocare l'intero oggetto sullo stack. Tuttavia, è concettualmente sul mucchio, se scegli di preoccuparti.


1
Informazioni sulla "escape analyisis" in Java: blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead Dice che è presente dal rilascio ad accesso anticipato di JDK 6 Update 14, e abilitato per impostazione predefinita dall'aggiornamento 23 JDK 6
Guido

cambia qualcosa se l'array è public static final? Non dovrebbe quindi far parte del pool costante?
Malachiasz

@Malachiasz: No. Un array non è mai una costante.
Jon Skeet

@ JonSkeet: in tutte le versioni della libreria Java di cui sono a conoscenza, ognuna Stringè supportata da un file char[]. Credo che le stringhe letterali siano memorizzate nel pool costante pubblico; per l'ottimizzazione GC, ciò implicherebbe che gli array di supporto dovrebbero essere memorizzati allo stesso modo (altrimenti il ​​pool di costanti dovrebbe essere scansionato durante qualsiasi ciclo GC in cui l'array di supporto sarebbe altrimenti idoneo per la raccolta).
supercat

@supercat: Sì, avrebbe senso. Ma qualsiasi array che dichiari di te stesso non finisce mai come parte del pool di costanti.
Jon Skeet

37

Verrà archiviato nell'heap

perché array è un oggetto in java.

EDIT : se hai

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

Pensa a questo codice come a dire al compilatore: "Crea un oggetto array che conterrà quattro interi e assegnalo alla variabile di riferimento denominata testScores. Inoltre, vai avanti e imposta ogni intelemento su zero. Grazie".


3
E la variabile di riferimento denominata testScores (che punta all'array sull'heap) sarà nello stack.
Zaki

11
Il codice dice "Grazie" solo se fornisci l' -gopzione al compilatore. Altrimenti verrà ottimizzato.
mafia

1
@mob Stai supponendo che questo sia l'unico codice. Probabilmente è meglio presumere che queste due righe facciano parte di un programma più ampio che utilizza effettivamente l'array.
Code-Apprentice

22

È un array di tipi primitivi che di per sé non è primitivo. Una buona regola pratica è quando è coinvolta la nuova parola chiave, il risultato sarà nell'heap.


19

Volevo solo condividere alcuni test che ho eseguito su questo argomento.

Matrice di dimensioni 10 milioni

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

Produzione:

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

Come puoi vedere, la dimensione dell'heap utilizzato è aumentata di ~ 80 MB, ovvero 10 m * di dimensione (doppia).

Ma se dobbiamo usare Double invece di double

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

L'output mostrerà 40 MB. Abbiamo solo riferimenti doppi, non sono inizializzati.

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

Ancora 40 MB. Perché puntano tutti allo stesso oggetto Double.

Inizializzazione con double invece

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

Linea

a[i] = qq.doubleValue();

è equivalente a

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

che è equivalente a

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

Poiché ogni volta creiamo nuovi oggetti Double, eliminiamo il mucchio. Ciò mostra che i valori all'interno della classe Double sono archiviati nell'heap.


1
Potresti incollare i dettagli del codice di memInfo () pls? :)
hedleyyan

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.