非プリミティブ (オブジェクト) がヒープに置かれ、メソッドがスタックに置かれることはわかっていますが、プリミティブ変数はどうでしょうか?
- アップデート
答えに基づいて、ヒープは特定のオブジェクトの新しいスタックとヒープを持つことができると言えますか? オブジェクトがプリミティブ変数と参照変数を持つことを考えると..?
非プリミティブ (オブジェクト) がヒープに置かれ、メソッドがスタックに置かれることはわかっていますが、プリミティブ変数はどうでしょうか?
- アップデート
答えに基づいて、ヒープは特定のオブジェクトの新しいスタックとヒープを持つことができると言えますか? オブジェクトがプリミティブ変数と参照変数を持つことを考えると..?
ローカルで定義されたプリミティブはスタック上にあります。ただし、プリミティブがオブジェクトのインスタンスの一部として定義されている場合、そのプリミティブはヒープ上にあります。
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
ヒープ上に割り当てられているため、int y
は のインスタンスの一部としてヒープ上にありますHeapClass
。
ただし、任意のメソッドの本体で宣言されたすべてのプリミティブ変数は、スタックにあります。
上記の例でわかるように、int x
は、クラスのメンバーとしてではなく、メソッド本体で宣言されているため、スタックにあります。
すべてのローカル変数 (メソッド引数を含む) はスタックに置かれます。オブジェクトとそのすべてのフィールドはヒープに格納されます。変数は常にプリミティブまたはオブジェクトへの参照です。
Java 実装は、実際には仕様に準拠した方法でオブジェクトをヒープに格納する場合があります。同様に、ローカル変数はレジスタに格納されたり、最適化によって不明確になったりする場合があります。
プリミティブは両方の場所にあります。
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 方式で割り当てることができます。それよりも新しいすべてのピースが割り当て解除されるまで、ピースの割り当てを解除することはできません。これは、コール スタックの使用方法と都合よく一致します。関数が戻ったときにそれが消えても問題ない限り、何でもスタックに置くことができます。これは最適化です。この方法での使用のみがサポートされているため、スタックからの割り当てと割り当て解除が非常に高速であるためです。必要に応じて、関数のすべてのローカル変数を実装のヒープに格納できます。ヒープはより柔軟であるため、使用コストが高くなります。私が言ったように、オブジェクトにスタックとヒープがあると言うのは正確ではありません。
プリミティブ値は、オブジェクトのフィールドでない限り、スタックに割り当てられます。オブジェクトのフィールドの場合は、ヒープに配置されます。スタックは評価と実行に使用されるため、プリミティブ フィールドを持つオブジェクトにスタックがあると言っても意味がありません。スタックは依然としてヒープの一部と見なされます。オブジェクトもStack
ヒープに割り当てられます。