web-dev-qa-db-ja.com

Javaスタックまたはヒープに格納されているプリミティブの配列?

次のような配列宣言があります。

int a[];

ここで、aはプリミティブint型の配列です。この配列はどこに保存されますか?ヒープまたはスタックに保存されていますか?これはプリミティブ型intであり、すべてのプリミティブ型がヒープに格納されるわけではありません。

81
user241924

グルクルキが言ったように、それはヒープに保存されます。しかし、あなたの投稿は、おそらく「プリミティブは常にスタックに住んでいる」という神話を広めている善意の人による誤解を示唆しています。これは真実ではありません。 ローカル変数スタックに値がありますが、すべてのプリミティブ変数がローカルではありません...

たとえば、これを考慮してください:

public class Foo
{
    int value;
}
...

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

ここで、f.value ライブ?神話は、それがスタック上にあることを示唆しますが、実際にはそれは新しいFooオブジェクトの一部であり、ヒープ上に存在します1。 (fの値自体が参照であり、スタック上に存在することに注意してください。)

そこから、配列への簡単なステップです。配列はただのたくさんの変数であると考えることができます-new int[3]は、この形式のクラスを持つようなものです。

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

1 実際、これよりも複雑です。スタック/ヒープの区別は、主に実装の詳細です-おそらく実験的なJVMは、オブジェクトがメソッドから「エスケープ」されず、スタック上のオブジェクト全体を割り当てることができることを認識できると信じています。ただし、気にすることを選択した場合、ヒープ上の概念的にです。

143
Jon Skeet

heapに保存されます

配列はJavaのオブジェクトだからです。

[〜#〜] edit [〜#〜]:持っている場合

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

このコードは、コンパイラに「4つのintを保持する配列オブジェクトを作成し、testScoresという名前の参照変数に割り当てます。また、各int要素を設定する」と考えてください。ゼロに。ありがとう。」

36
GuruKulki

それはプリミティブ型の配列であり、それ自体はプリミティブではありません。良い経験則は、新しいキーワードが関係する場合、結果はヒープ上にあるということです。

20

このテーマで実行したいくつかのテストを共有したかっただけです。

サイズ1000万の配列

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

出力:

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

ご覧のとおり、使用済みヒープサイズは最大80 MB増加します。これは10m * sizeof(double)です。

しかし、doubleの代わりにDoubleを使用している場合

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

出力には40MBが表示されます。 Double参照のみがあり、初期化されていません。

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

まだ40MB。それらはすべて同じDoubleオブジェクトを指しているためです。

代わりに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

ライン

a[i] = qq.doubleValue();

に等しい

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

これは

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

毎回新しいDoubleオブジェクトを作成するため、ヒープを吹き飛ばします。これは、Doubleクラス内の値がヒープに格納されていることを示しています。

15
acheron55

Javaプログラミング言語の配列はオブジェクトであり、動的に作成され、Object型の変数に割り当てることができます。

http://Java.Sun.com/docs/books/jls/second_edition/html/arrays.doc.html

2