Ist ein Java-Array von Grundelementen in einem Stapel oder Heap gespeichert?

83

Ich habe eine Array-Deklaration wie folgt:

int a[];

Hier aist ein Array vom primitiven intTyp. Wo ist dieses Array gespeichert? Wird es auf einem Haufen oder Stapel gespeichert? Dies ist ein primitiver Typ int. Alle primitiven Typen werden nicht auf dem Heap gespeichert.

user241924
quelle
38
Das ist kein Array. Es ist eine Referenz auf ein Array. Die Referenz selbst kann auf dem Heap gespeichert werden, wenn sie Mitglied einer Klasse oder eines Objekts ist, oder auf dem Stapel, wenn es sich um eine lokale Variable in einer Methode handelt. Und primitive Typen können auf dem Heap gespeichert werden, wenn sie Mitglieder einer Klasse oder eines Objekts sind.
Onkel O

Antworten:

143

Wie Gurukulki sagte, ist es auf dem Haufen gespeichert. Ihr Beitrag deutete jedoch auf ein Missverständnis hin, wahrscheinlich aufgrund einer gut gemeinten Person, die den Mythos verbreitet, dass "Primitive immer auf dem Stapel leben". Das ist falsch. Lokale Variablen haben ihre Werte auf dem Stapel, aber nicht alle primitiven Variablen sind lokal ...

Betrachten Sie zum Beispiel Folgendes:

public class Foo
{
    int value;
}
...

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

Nun, wo tut f.value wohnt nun? Der Mythos würde vorschlagen, dass es auf dem Stapel liegt - aber tatsächlich ist es Teil des neuen FooObjekts und lebt auf dem Haufen 1 . (Beachten Sie, dass der Wert von sich fselbst eine Referenz ist und auf dem Stapel lebt.)

Von dort ist es ein einfacher Schritt zu Arrays. Sie können sich ein Array nur als eine Menge Variablen vorstellen - also new int[3]ein bisschen wie eine Klasse dieser Form:

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

1 Tatsächlich ist es komplizierter. Die Unterscheidung zwischen Stapel und Heap ist meistens ein Implementierungsdetail. Ich glaube, einige JVMs, möglicherweise experimentelle, können erkennen, wann ein Objekt niemals einer Methode "entkommt", und können das gesamte Objekt auf dem Stapel zuordnen. Es ist jedoch konzeptionell auf dem Haufen, wenn Sie sich dafür interessieren.

Jon Skeet
quelle
1
Über die "Escape-Analyse" in Java: blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead Es heißt, dass sie seit der frühen Zugriffsversion von JDK 6 Update 14 und vorhanden ist standardmäßig aktiviert seit JDK 6 Update 23.
Guido
ändert es etwas, wenn das Array öffentlich statisch endgültig ist? Sollte es dann nicht Teil des konstanten Pools sein?
Malachiasz
@ Malachiasz: Nein. Ein Array ist niemals eine Konstante.
Jon Skeet
@ JonSkeet: In allen mir bekannten Versionen der Java-Bibliothek wird jede Stringvon a unterstützt char[]. Ich glaube, dass wörtliche Zeichenfolgen im öffentlichen konstanten Pool gespeichert sind. Für die GC-Optimierung würde dies bedeuten, dass die Backing-Arrays ebenfalls gespeichert werden sollten (andernfalls müsste der konstante Pool während eines GC-Zyklus gescannt werden, in dem das Backing-Array ansonsten zur Sammlung berechtigt wäre).
Supercat
@ Supercat: Ja, das würde Sinn machen. Aber jedes Array, das Sie selbst deklarieren, wird niemals Teil des konstanten Pools.
Jon Skeet
37

Es wird auf dem Haufen gespeichert

weil Array ein Objekt in Java ist.

EDIT : wenn du hast

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

Stellen Sie sich diesen Code so vor, als würde er dem Compiler sagen: "Erstellen Sie ein Array-Objekt, das vier Ints enthält, und weisen Sie es der Referenzvariablen mit dem Namen zu testScores. Setzen Sie außerdem jedes intElement auf Null. Danke."

GuruKulki
quelle
2
Die Referenzvariable mit dem Namen testScores (die auf das Array auf dem Heap zeigt) befindet sich auf dem Stapel.
Zaki
11
Der Code sagt nur "Danke", wenn Sie -gdem Compiler die Option zur Verfügung stellen. Andernfalls wird es weg optimiert.
Mob
1
@mob Sie gehen davon aus, dass dies der einzige Code ist. Es ist wahrscheinlich besser anzunehmen, dass diese beiden Zeilen Teil eines größeren Programms sind, das das Array tatsächlich verwendet.
Code-Apprentice
21

Es ist eine Reihe von primitiven Typen, die an sich nicht primitiv sind. Eine gute Faustregel lautet: Wenn das neue Schlüsselwort betroffen ist, befindet sich das Ergebnis auf dem Heap.

Esben Skov Pedersen
quelle
17

Ich wollte nur ein paar Tests teilen, die ich zu diesem Thema durchgeführt habe.

Array mit einer Größe von 10 Millionen

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

Ausgabe:

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

Wie Sie sehen, wird die Größe des verwendeten Heapspeichers um ~ 80 MB erhöht, was einer Größe von 10 m * (doppelt) entspricht.

Aber wenn wir Double anstelle von Double verwendet haben

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

Die Ausgabe zeigt 40 MB. Wir haben nur Doppelreferenzen, sie werden nicht initialisiert.

Füllen Sie es mit 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();
}

Immer noch 40 MB. Weil sie alle auf dasselbe Double-Objekt zeigen.

Initialisierung stattdessen mit 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.doubleValue();
    }
    memInfo();
}

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

Linie

a[i] = qq.doubleValue();

ist äquivalent zu

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

das ist äquivalent zu

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

Da wir jedes Mal neue Double-Objekte erstellen, blasen wir den Heap aus. Dies zeigt, dass Werte innerhalb der Double-Klasse im Heap gespeichert sind.

acheron55
quelle
1
Könnten Sie das Codedetail von memInfo () pls einfügen? :)
Hedleyyan