私の理解では、Javaのガベージコレクションは、他のオブジェクトがそのオブジェクトを「ポイント」していない場合、そのオブジェクトをクリーンアップします。
私の質問は、次のようなものがあるとどうなるかです。
class Node {
public object value;
public Node next;
public Node(object o, Node n) { value = 0; next = n;}
}
//...some code
{
Node a = new Node("a", null),
b = new Node("b", a),
c = new Node("c", b);
a.next = c;
} //end of scope
//...other code
a
、b
、およびc
はガベージコレクションされる必要がありますが、それらはすべて他のオブジェクトによって参照されています。
Javaガベージコレクションはこれをどのように処理しますか?(または単にメモリドレインですか?)
JavaのGCは、ガベージコレクションルートから始まるチェーンを介してオブジェクトに到達できない場合、オブジェクトを「ガベージ」と見なします。したがって、これらのオブジェクトは収集されます。オブジェクトが相互に指し合ってサイクルを形成している場合でも、ルートから切り離された場合、それらは依然としてゴミです。
厄介な詳細については、「付録A:ガベージコレクションについての真実 Javaプラットフォームパフォーマンス:戦略と戦術 」の到達不能オブジェクトに関するセクションを参照してください。
yes Javaガベージコレクターは循環参照を処理します!
How?
ガベージコレクションルート(GCルート)と呼ばれる特別なオブジェクトがあります。これらは常に到達可能であり、独自のルートにあるオブジェクトも同様です。
単純なJavaアプリケーションには次のGCルートがあります。
使用されなくなったオブジェクトを判別するために、JVMはマークアンドスイープアルゴリズムと呼ばれるものを断続的に実行します。次のように動作します
そのため、GCルートから到達できないオブジェクトがある場合(自己参照または循環参照であっても)、ガベージコレクションの対象になります。
もちろん、プログラマがオブジェクトの逆参照を忘れると、メモリリークが発生することがあります。
ソース: Javaメモリ管理
ガベージコレクターは、CPUレジスタ、スタック、グローバル変数など、常に「到達可能」と見なされる場所の「ルート」セットから始まります。それらの領域でポインターを見つけ、それらが指すすべてを再帰的に見つけることで機能します。それがすべて見つかると、everything elseはごみです。
もちろん、主に速度のために、かなりの数のバリエーションがあります。たとえば、最新のガベージコレクターは「世代別」です。つまり、オブジェクトを世代に分割します。オブジェクトが古くなると、ガベージコレクターは、そのオブジェクトがまだ有効かどうかを判断しようとする時間をますます長くします。 -長い間住んでいれば、さらに長く生き続ける可能性がかなり高いと仮定し始めただけです。
それにもかかわらず、基本的な考え方は同じままです。それは、当然のことながら、使用できる可能性のあるルートセットから開始し、すべてのポインタを追跡して、他に使用可能なものを見つけることに基づいています。
興味深いことに、ガベージコレクターのこの部分と、リモートプロシージャコールなどのオブジェクトをマーシャリングするためのコードとの類似性の程度に、人々が驚かされることがよくあります。いずれの場合も、オブジェクトのルートセットから開始し、参照する他のすべてのオブジェクトを見つけるためにポインターを追跡しています...
あなたは正しいです。説明するガベージコレクションの特定の形式は、「参照カウント」と呼ばれます。最も単純な場合の動作方法(概念的には、少なくとも、最新の参照カウントの実装は実際にはまったく異なる方法で実装されます)は、次のようになります。
そして、この単純な戦略にはまさにあなたが説明する問題があります.AがBを参照し、BがAを参照する場合、その両方の参照カウントはneverが1未満になる可能性があり、収集されないことを意味します。
この問題に対処するには、4つの方法があります。
ちなみに、otherガベージコレクターを実装する主要な方法(および、上記の2、3回のことを既に示唆しました)はtracingです。トレースコレクタは、到達可能性の概念に基づいています。まず、root setであることがわかっているalways到達可能(たとえば、グローバル定数、またはObject
クラス、現在のレキシカルスコープ、現在のスタックフレーム)そしてそこからtraceルートセットから到達可能なすべてのオブジェクト、ルートセットから到達可能なオブジェクトから到達可能なすべてのオブジェクトなど、推移的閉包が得られるまで。そのクロージャーでnotであるものはすべてゴミです。
サイクルはそれ自体内でのみ到達可能であり、ルートセットからは到達できないため、収集されます。
Java GCは実際には説明どおりに動作しません。「GCルート」と呼ばれることが多いオブジェクトの基本セットから開始し、ルートからは到達できません。
GCルートには次のようなものが含まれます。
したがって、あなたの場合、ローカル変数a、b、およびcがメソッドの最後にスコープから外れると、3つのノードのいずれかへの参照を直接または間接的に含むGCルートはなくなります。ガベージコレクションの対象になります。
豆腐ビールのリンクには、必要に応じて詳細が記載されています。
この記事 (使用できなくなりました)ガベージコレクターについて詳しく説明します(概念的には、いくつかの実装があります)。投稿に関連する部分は「A.3.4到達不能」です。
A.3.4到達不能オブジェクトは、それに対する強力な参照が存在しなくなると到達不能状態になります。オブジェクトが到達不能である場合、それはコレクションの候補です。言い回しに注意してください:オブジェクトがコレクションの候補であるからといって、すぐに収集されるわけではありません。 JVMは、オブジェクトがメモリを消費することがすぐに必要になるまで、収集を遅らせることができます。
ガベージコレクションは、通常、「他のオブジェクトがそのオブジェクトを「指している」場合にのみ、オブジェクトをクリーンアップする」ことを意味しません(参照カウント)。ガベージコレクションとは、おおよそ、プログラムから到達できないオブジェクトを見つけることを意味します。
したがって、あなたの例では、a、b、およびcがスコープから外れると、これらのオブジェクトにアクセスできなくなるため、GCによって収集できます。
ビルはあなたの質問に直接答えました。アムノンが言ったように、ガベージコレクションの定義は単なる参照カウントです。マークアンドスイープやコピーコレクションなどの非常に単純なアルゴリズムでも、循環参照を簡単に処理できることを追加したかっただけです。だから、それについて魔法はありません!