web-dev-qa-db-ja.com

Javaプリミティブはスタックまたはヒープに配置されますか?

非プリミティブ(オブジェクト)がヒープに行き、メソッドがスタックに行くことを知っていますが、プリミティブ変数はどうですか?

-update

回答に基づいて、ヒープは特定のオブジェクトの新しいスタックとヒープを持つことができますか?オブジェクトにプリミティブ変数と参照変数があることを考えると..?

55
Tom Brito

ローカルで定義されたプリミティブはスタック上にあります。ただし、プリミティブがオブジェクトのインスタンスの一部として定義されている場合、そのプリミティブはヒープ上にあります。

_public class Test {
    private static class HeapClass {
        public int y; // When an instance of HeapClass is allocated, this will be on the heap.
    }
    public static void main(String[] args) {
        int x=1; // This is on the stack.
    }
}
_

更新に関して:

オブジェクトには独自のスタックはありません。私の例では、_int y_は実際にはHeapClassの各インスタンスの一部になります。 HeapClassのインスタンスが割り当てられると(例:new Test.HeapClass())、HeapClassのすべてのメンバー変数がヒープに追加されます。したがって、HeapClassのインスタンスはヒープに割り当てられているため、HeapClassのインスタンスの一部として_int y_がヒープに配置されます。

ただし、メソッドの本体で宣言されたすべてのプリミティブ変数は、スタック上でになります

上記の例でわかるように、_int x_はクラスのメンバーとしてではなくメソッド本体で宣言されているため、スタック上にあります。

85
Jack Edmonds

すべてのローカル変数(メソッド引数を含む)はスタックに置かれます。オブジェクトとそのすべてのフィールドはヒープに格納されます。変数は常にプリミティブまたはreferencesオブジェクトです。

Java実装は、仕様に準拠するように、実際にオブジェクトをヒープに格納する場合があります。同様に、ローカル変数はレジスタに保存されるか、最適化によって不明瞭になる場合があります。

19

プリミティブは両方の場所にあります。

class Foo
{
   public int x;
   public static void Main()
   {
      int y = 3; // y is on the stack
      Foo f = new Foo();  // f.x is probably on the heap
   } 
}

ただし、JVMを構築しているのでない限り、あまり気にする必要はありません。本当に賢いオプティマイザーは、fが指すFooは決してMainをエスケープせず、スタックに割り当てるのに安全な別の関数に渡されないことを決定するかもしれません。

更新に関して:

スタックとヒープは、それらに格納されているものではなく、それらに提供される操作によって区別されます。スタックを使用すると、メモリの一部をLIFOのように割り当てることができます。それよりも若い部分がすべて割り当て解除されるまで、部分の割り当てを解除することはできません。スタックが使用されます。関数が戻ったときに、そのものが消えても問題ない限り、スタックに何でも置くことができます。これは最適化です。必要に応じて、実装のヒープ上の関数のすべてのローカル変数を格納できます。ヒープはより柔軟性があり、その結果、使用するのにより高価になります。私が言ったように、スタックとヒープは、スタックとヒープを区別するのは、その中にあるものではなく、利用可能な操作です。

10
Logan Capaldo

プリミティブ値は、オブジェクトのフィールドである場合を除き、スタックに割り当てられます。オブジェクトのフィールドでは、ヒープに配置されます。スタックは評価と実行に使用されるため、プリミティブフィールドを持つオブジェクトがスタックを持っていると言っても意味がありません。これはヒープの一部と見なされます。 Stackオブジェクトもヒープに割り当てられます。

7
Mark Cidade