ヒープ メモリは Java でガベージ コレクションされます。
スタックガベージも収集されますか?
スタックメモリはどのように再利用されますか?
ヒープ メモリは Java でガベージ コレクションされます。
スタックガベージも収集されますか?
スタックメモリはどのように再利用されますか?
スタック上のメモリには、メソッド パラメーターとローカル変数 (正確には、オブジェクトの参照とプリミティブ型の変数自体) が含まれます。メソッドを離れると、それは自動的に削除されます。変数が (オブジェクトへの) 参照である場合、オブジェクト自体はヒープ上にあり、ガベージ コレクターによって処理されます。
したがって、スタックはヒープと同じ方法でガベージ コレクションされるわけではありませんが、スタックは独自の自動メモリ管理の形式です (これはガベージ コレクションよりも前から行われています)。
より詳細な回答が Thomas Pornin によって提供されています。詳細については、それを調べてください。
Java では、スタックはガベージ コレクションされません。
特定のメソッド呼び出しに割り当てられたスタックは、メソッドが戻るときに解放されます。これは非常に単純な LIFO 構造であるため、ガベージ コレクションは必要ありません。
スタックとガベージ コレクションが相互作用する 1 つの場所は、スタック上の参照が GC ルートであることです (つまり、到達可能性が決定されるルート参照であることを意味します)。
スタックはガベージ コレクションされる可能性があります。ただし、ほとんどの JVM 実装では、定義上、ガベージ コレクションを排除する「スタック」として処理されます。
スタックと呼ばれるものは、メソッド起動コンテキストの蓄積です。呼び出されたメソッドごとに、これはメソッド引数、ローカル変数、呼び出しメソッドのコンテキストへの隠しポインター、および命令を保存するスロットを含む概念構造です。ポインター。Java 言語自体からアクティベーション コンテキストにアクセスすることはできません。メソッドが終了すると、コンテキストは役に立たなくなります (return
またはスローされた例外のため)。メソッド A がメソッド B を呼び出すと、A が制御を取り戻したときに、B のコンテキストが役に立たなくなることが保証されます。これは、B のコンテキストの有効期間が A のコンテキストの有効期間の部分範囲であることを意味します。したがって、アクティブ化コンテキスト (特定のスレッドの) は、LIFO (「後入れ先出し」) 規律で割り当てることができます。簡単に言えば、スタック: 新しいアクティブ化コンテキストがコンテキストのスタックの上にプッシュされ、一番上のコンテキストが最初に破棄されます。
実際には、アクティベーション コンテキスト (スタック フレームとも呼ばれます) は、スタックの順序で専用の領域に連結されます。その領域は、スレッドの開始時にオペレーティング システムから取得され、オペレーティング システムはスレッドの終了時にそれを取得します。スタックの最上位は特定のポインターによって指定され、多くの場合、CPU レジスターに含まれています (これは、JVM がコードを解釈しているかコンパイルしているかによって異なります)。「呼び出し元のコンテキストへのポインター」は仮想です。呼び出し元のコンテキストは、必ずスタック順ですぐ下に配置されます。GC は介入しません。スタックの領域は、スレッド アクティビティ自体から同期的に作成および再利用されます。これは、GC をまったく持たないCなどの多くの言語でも機能します。
現在、JVM 実装が他のことを行うことを妨げるものは何もありません。たとえば、アクティベーション コンテキストをヒープに割り当てて、それらを GC で収集します。スタック割り当ての方が高速であるため、これは通常、Java 仮想マシンでは行われません。しかし、他のいくつかの言語、特にGC を使用しながら継続を扱う言語 (例えば、 Schemeとそのcall-with-current-continuation
関数) は、そのようなことを行う必要があります。
メモリのスタック部分は、「スタック」のように機能します。私はそれが悪いように聞こえることを知っています、しかしそれはまさにそれがどのように機能するかです。データは上部に追加され( )、プログラムの実行時pushed onto the stack
に自動的に上部から削除されます()。popped off the stack
ガベージコレクションではありません。データがスタックからポップされると、そのメモリは自動的に再利用されるため、ガベージコレクションする必要はありません。そして、再生されたと言っても、割り当てが解除されるわけではありません。データがポップオフされるため、次のデータが格納されるスタックメモリ内の場所が減少するだけです。
もちろん、スタックについてまったく心配する必要がないというわけではありません。再帰関数を何度も実行すると、最終的にすべてのスタックスペースが使い果たされます。多くの関数を呼び出す場合、特にそれらに多くのパラメーターやローカル変数がある場合も同じです。
しかし、肝心なのは、関数がスコープに出入りするときに、スタックのメモリが自動的に使用され、再利用されるということです。したがって、プログラムの実行が終了すると、すべてのスタックメモリが解放され、オペレーティングシステムに解放されます。
スタックで使用されているメモリを参照すると、ガベージコレクションは行われません。
Java仮想マシンは、明示的なバイトコード命令を使用してスタック上のメモリを予約および解放します。これらの命令はコンパイラによって生成され、スタック上のint、boolean、double、object-referencesなどのプリミティブの存続期間を管理します。
いわゆる末尾呼び出しの最適化を実装する計画があります。これは、使用されなくなったことがわかったらスタックから一部のエントリを削除しますが、これをすでにサポートしているjvmはわかりません。
したがって、スタック自体のガベージコレクションはなく、メモリ使用量を管理するためにコンパイラが生成したプッシュおよびポップ命令のみがあります。
スタック自体はスレッドの一部です。スタックは、スレッドオブジェクトが作成され、スレッドが終了してスレッドオブジェクトが参照されなくなった後にガベージコレクションが行われるときに割り当てられます。
Javaのすべてのオブジェクトは、ヒープに割り当てられます。(少なくとも仕様に関する限り、実際の実装では、ヒープ上にあるかのように透過的に動作する場合、スタックに割り当てることができます。)
正確に収集できるものは少し微妙です。オブジェクトへの唯一の参照が単一のスタックフレーム内にあり、参照が再度使用されないことを示すことができる場合、オブジェクトが収集される可能性があります。オブジェクトがフィールドの読み取りにのみ使用される場合、そのフィールドの読み取りは前方に最適化され、オブジェクトは予想よりも早く収集される可能性があります。
ファイナライザー(またはおそらくReference
s)を使用していない限り、これは通常は問題になりません。その場合は注意が必要であり、happens-before
関係を強制するためにロック/揮発性を使用する必要があります。
スレッドが停止すると、通常、スタック全体の割り当てが解除されます。
いいえ。 Java では、スタックはガベージ コレクションされません。各スレッドには独自のスタックがあり、以下が含まれます。
これらの値は、メソッド呼び出しごとにスタック フレームとしてスタックにプッシュされます。スタックは「後入れ先出し」の順序に従うため、すべてのメソッド呼び出しの最後に、すべてのメソッド固有のデータとオブジェクトへの参照 (存在する場合) を含む各スタック フレームがポップアウトされます。
したがって、メソッド/プログラムが範囲外になると、スタック内のデータは自動的に消去されます。
メソッドの呼び出し中などに内部変数があるため、スタックからデータがプッシュおよびポップされます。これを気にする必要はありません。
スタック上にあるものはすべて、ガベージ コレクターによってグローバル ルートとして扱われます。つまり、スタックは「ガベージ コレクション」であると断言できます。