スタックガベージはJavaで収集されていますか?
-
20-09-2019 - |
質問
ヒープメモリは、Javaで収集されたゴミです。
スタックガベージも収集されていますか?
スタックメモリはどのように再生されますか?
正しい解決策はありません
他のヒント
スタックのメモリには、メソッドパラメーターとローカル変数が含まれています(正確には、原始タイプのオブジェクトと変数の参照)。メソッドを離れると、自動的に削除されます。変数が参照(オブジェクトに対する)の場合、オブジェクト自体がヒープ上にあり、ガベージコレクターによって処理されます。
したがって、スタックはヒープと同じように収集されたガベージではありませんが、スタックは独自の自動メモリ管理の形式です(ゴミコレクションよりも前)。
a より詳細な答えは、トーマス・ポルニンによって与えられます, 、詳細については、それをご覧ください。
スタックはJavaで収集されたゴミではありません。
特定のメソッド呼び出しに割り当てられたスタックは、メソッドが返されると解放されます。それは非常にシンプルなLIFO構造であるため、ごみ収集は必要ありません。
スタックとガベージコレクションが相互作用する場所の1つは、スタックの参照がGCルーツであることです(これは、それらが到達可能性が決定されるルート参照であることを意味します)。
スタック できる 収集されたゴミになります。ただし、ほとんどのJVM実装では、「スタック」として処理されます。これは、定義上、ゴミコレクションを排除します。
私たちがスタックと呼ぶのは、の蓄積です メソッドアクティベーションコンテキスト: :呼び出された各方法について、これはメソッド引数、ローカル変数、呼び出しメソッドのコンテキストへの隠されたポインター、および命令ポインターを保存するためのスロットを含む概念構造です。アクティベーションコンテキストは、Java言語自体からそのようにアクセスできません。メソッドが終了すると、コンテキストは役に立たなくなります( return
またはスローされた例外のため)。メソッドAがメソッドBを呼び出すと、aがコントロールを取り戻すと、Bのコンテキストが役に立たないことが保証されます。これは、Bのコンテキストの寿命がAのコンテキストの寿命のサブレンジであることを意味します。したがって、アクティベーションコンテキスト(特定のスレッドの場合)は、LIFO(「Last In、Out」)規律で割り当てることができます。簡単に言えば、スタック:新しいアクティベーションコンテキストがコンテキストのスタックの上にプッシュされ、上のコンテキストが最初に処分されます。
実際には、アクティベーションコンテキスト(呼ばれます スタックフレーム)専用の領域で、スタック順に連結されます。その領域は、スレッドが開始されたときにオペレーティングシステムから取得され、オペレーティングシステムはスレッドが終了したときにそれを取り戻します。スタックの上部は、多くの場合、CPUレジスタに含まれる特定のポインターで指定されます(これは、JVMがコードを解釈またはコンパイルしているかどうかによって異なります)。 「発信者のコンテキストへのポインター」は仮想です。発信者のコンテキストは、必然的にスタック順のすぐ下にあります。 GCは介入しません。スタックの領域が作成され、スレッドアクティビティ自体から同期して回収されます。これはまた、そのような多くの言語で機能する方法でもあります c, 、GCをまったく持っていません。
これで、JVMの実装が他の方法で実行されるのを防ぐものは何もありません。たとえば、ヒープ内のアクティベーションコンテキストを割り当て、GCによって収集することを妨げます。これは通常、スタックの割り当てがより速くなるため、Java仮想マシンでは行われません。しかし、他のいくつかの言語はそのようなことをする必要があります、最も顕著な言語は 継続 まだGCを使用している間(例: 図式 そしてその call-with-current-continuation
関数)、そのようなゲームは上記のLIFOルールを破るためです。
メモリのスタック部分は、「スタック」のように機能します。私はそれが悪いように聞こえることを知っていますが、それがまさにそれがどのように機能するかです。データが上部に追加され、互いに上に追加されます(pushed onto the stack
)そして、上部から自動的に削除されます(popped off the stack
)プログラムが実行されると。収集されたガベージではありません。また、データがスタックからポップアップされると、そのメモリが自動的に回収されるため、そうである必要はありません。そして、私が回収されたと言うとき、私はそれが解釈されるという意味ではありません - それは、データが飛び出すにつれて、次のデータが保存されるスタックメモリ内の場所が減少するということです。
もちろん、それはスタックについてまったく心配する必要がないということではありません。再帰機能を何度も実行すると、最終的にすべてのスタックスペースが使い果たされます。多くの関数を呼び出す場合、特に多くのパラメーターやローカル変数がある場合も同じです。
しかし、一番下の行では、スタックのメモリが使用され、関数がスコープを自動的に除外して出発するときに回収されます。そのため、プログラムの実行の最後に、すべてのスタックメモリが無料になり、オペレーティングシステムにリリースされます。
スタックで使用されるメモリを参照する場合、収集されたゴミではありません。
Java Virtual Machineは、明示的なバイトコード命令を使用してスタックのメモリを予約および解放します。これらの命令はコンパイラによって生成され、スタックのINT、ブール、ダブル、オブジェクトリファレンスなどのプリミティブの寿命を管理します。
いわゆるテールコールの最適化を実装する計画がありました。これにより、使用されなくなったことがわかっていれば、スタックからいくつかのエントリが削除されますが、すでにこれをサポートしているJVMはわかりません。
したがって、スタック自体にガベージコレクションはありません。コンパイラのみがメモリの使用を管理するためのプッシュとポップの指示を生成しました。
スタック自体はスレッドの一部です。スレッドオブジェクトが作成され、スレッドが終了し、スレッドオブジェクトがもはや参照されなくなった後にガベージが収集されると、スタックが割り当てられます。
Javaのすべてのオブジェクトは、ヒープに割り当てられます。 (少なくとも仕様に関する限り、実際の実装は、それらがヒープにいるかのように透過的に動作する場合、スタックにそれらを割り当てることができます。)
まさに収集可能なものは少し微妙です。オブジェクトへのみの参照が単一のスタックフレームにある場合、参照が再度使用されないことを示すことができる場合、オブジェクトは収集される場合があります。オブジェクトがフィールドの読み取りにのみ使用される場合、そのフィールド読み取りは前方に最適化され、予想よりも早く収集されたオブジェクトが最適化される場合があります。
これは通常、ファイナイザーを使用していない限り(またはおそらく問題ではありません Reference
s)。その場合、注意し、ロック/揮発性を使用して happens-before
関係。
スレッドが停止すると、通常、スタック全体が扱われます。
スタックにあるものはすべて、ゴミコレクターによってグローバルなルーツとして扱われます。したがって、はい、スタックは「ごみ収集」であると間違いなく言うことができます。
メソッド、メソッド呼び出しなどに内部変数があるため、データはプッシュされ、スタックからポップされません。これを気にする必要はありません。
いいえ。スタックはJavaで収集されたゴミではありません。各スレッドには独自のスタックがあり、以下が含まれています。
- メソッド固有の値(短命です)と
- ヒープで作成され、メソッドによって参照されているオブジェクトへの参照
これらの値は、すべてのメソッド呼び出しのスタックにスタックフレームとしてプッシュされます。スタックはすべてのメソッド呼び出しの終了時に「最後の最初のアウト」順序に続くため、すべてのメソッド固有のデータとオブジェクトへの参照を含む各スタックフレームがポップアウトされます。
したがって、メソッド/プログラムが範囲外になると、スタック内のデータは自動的にクリーニングされます。