オープニングの紹介
GCとは? なぜGCが必要なのでしょうか?
JavaにはGC機能があり、オブジェクトがスコープ外になったかどうかを自動的に監視し、メモリーを再利用します。 Java言語には、割り当てられたメモリーを解放する明示的な方法はありません。ヒープでは、もはや役に立たないオブジェクトが発見され、それらが占める領域が再利用できるように取り戻されます。ゴミ回収を要求するには、以下のメソッドのいずれかを呼び出します。
- System.gc()
Runtime.getRuntime().gc()
.
アルゴリズムのアイデア:すべてのオブジェクトのコレクションを形成するために、またはツリー構造として理解することができ、ツリーのルートから始まる見つけることができる限り、アクティブなオブジェクトである見つけることができない場合は、リサイクルする必要があります。
JavaのGCはどのようなメモリを回収する必要がありますか?
メモリ・ランタイム JVMには、メモリを管理するためのランタイム・データ領域があります。主に5つの部分から構成されています:
- プログラムカウンタ
- 仮想マシンスタック
- ネイティブメソッドスタック
- メソッド領域
- ヒープ
そしてその中でも、プログラムカウンタ、仮想マシンスタック、ローカルメソッドスタックは、スレッドごとにプライベートなメモリ空間であり、スレッドとともに生き、スレッドとともに死にます。例えば、スタック内の各スタックフレームにどれだけのメモリが割り当てられるかは、基本的にクラス構造でどれかが決まればわかるので、この3つの領域でのメモリ割り当てと再利用は決まっており、メモリ再利用の問題を考える必要はありません。しかし、メソッド領域とヒープは異なり、インタフェースの複数の実装が必要とするメモリは同じではないかもしれません、プログラムの実行時にのみ、どのようなオブジェクトが作成されるかを知ることができます、メモリのこの部分の割り当てと回収は動的であり、GCは主にメモリのこの部分に関係しています。
要約すると、GCが回収する主なメモリはJVMのメソッド領域とヒープです。
一般的なゴミ回収業者の紹介
- シリアル・コレクター:シングルスレッド・コレクター、ゴミを集めるときは世界を止めなければならない、コピー・アルゴリズムを使用。
- ParNew コレクター:Serial コレクターのマルチスレッド版で、レプリケーション・アルゴリズムである STOP THE WORLD も必要です。
- 並列Scavengeコレクター:Cenozoicコレクター、レプリケーションアルゴリズム用コレクター、管理可能なスループットを達成することを目的とした並列マルチスレッドコレクター。VMが合計100分間実行され、そのうち1分間がゴミに費やされる場合、スループットは99%。
- Serial Old Collector: Serial コレクターの古いバージョンで、タグ照合アルゴ リズムを使用するシングルスレッドコレクターです。
- Parallel Old Collector: Parallel Scavenge Collector の古いバージョンで、マルチスレッドのマークソートアルゴリズムを使用しています。
Parallel Scavenge
: は、最短の回収休止時間を得ることを目的としたコレクタで、最初のマーキング、同時マーキング、再マーキング、同時クリア、および回収終了時の大量のスペース残骸で動作するマーク・アンド・クリーン・アルゴリズムです。- G1 コレクター:マーカー照合アルゴリズムの実装、操作フローは主に次のとおりです:初期マーキング、同時マーキング、最終マーキング、フィルタリングマーキング。スペースの断片化は発生せず、停止は正確に制御できます。
CMSコレクターとG1コレクターの違いは?
- CMS コレクタは古い時間のコレクタで、新しい時間の Serial および ParNew コレクタと使用できます。G1 コレクタは古い時間のコレクタと新しい時間 のコレクタを収集し、他のコレクタと組み合わせる必要はありません。
- CMSコレクターはダウンタイムを最小限に抑えるコレクターをターゲットに、G1コレクターはゴミ収集のダウンタイムを予測
- CMSコレクターは "mark-and-clean "アルゴリズムによるゴミ収集であり、メモリの断片化を起こしやすい。一方、G1コレクターは "mark-and-sort "アルゴリズムを使用しており、空間連結を行い、メモリ空間の断片化を軽減します。
GCの収集方法にはどのようなものがありますか?それぞれの原理や特徴を詳しく教えてください。
Mark-Clear Algorithmルートノードから順に、到達可能な全てのオブジェクトにマークを付け、マークが付いていない残りはゴミオブジェクトとし、クリアを行います。しかし、リサイクル後の空間は連続的ではありません。マーククリアアルゴリズムは、ルートコレクションからのスキャンを使用して、生き残っているオブジェクトをマークし、マークが完了した後、マークされていないオブジェクトのために空間全体をスキャンし、リサイクルを実行します。mark-clearアルゴリズムはオブジェクトを移動する必要がなく、非生存オブジェクトのみを処理するため、生存オブジェクトが多い場合は非常に効率的ですが、mark-clearアルゴリズムは非生存オブジェクトを直接リサイクルするため、メモリの断片化を引き起こす可能性があります。
コピーアルゴリズムコピーアルゴリズムは、ルートコレクションからのスキャンを使用し、生き残ったオブジェクトを新しい未使用のスペースにコピーします。 このアルゴリズムは、コントロールの生き残りオブジェクトが少ない場合、非常に効率的ですが、オブジェクトの移動のためにメモリのスワップスペースが必要になります。つまり、s0、s1などのスペースです。
Mark-Cleanup法Mark-Cleanupアルゴリズムは、Mark-Clearアルゴリズムと同じ方法でオブジェクトのマーキングを行いますが、クリア時に、生存していないオブジェクトによって占有されているスペースを取り戻した後、生存しているオブジェクトのネットの左端にある空きスペースをすべて移動し、対応するポインタを更新します。Mark-and-Cleanアルゴリズムは、Mark-and-Clearアルゴリズムに基づき、オブジェクトを移動させるため、よりコストがかかりますが、メモリの断片化の問題を解決します。
JavaのGCはいつゴミを集めるのか?
ヒープ内のオブジェクトについては、オブジェクトがまだ参照を持っているかどうかを判断するために到達可能性分析が使用されます。参照には4つのタイプがあり、それぞれ参照の実際の必要性に応じて回復メカニズムが異なります。メソッド領域内の定数とクラスについては、定数がどのオブジェクトからも参照されていない場合、その定数を取り戻すことができます。クラスについては、それが無用なクラスであると判断できれば、再利用することができます。
物体が生きているかどうかを見分けるには?
オブジェクトが生きているかどうかを判断する方法は2つあります:1.参照カウント法いわゆる参照カウント法とは、各オブジェクトに参照カウンタを設定し、オブジェクトへの参照があるたびにカウンタを1増やし、参照が無効な場合はカウンタを1減らします。オブジェクトの参照カウンタが0になると、そのオブジェクトは参照されていない、つまり「死んだオブジェクト」であり、ゴミとして回収されることを意味します。つまり、オブジェクト A がオブジェクト B を参照し、オブジェクト B がオブジェクト A を参照する場合、オブジェクト A と B の参照カウンタが 0 にならず、ゴミの収集が完了しないため、主流の仮想マシンではこのアルゴリズムを使用していません。
2.到達可能性アルゴリズムこのアルゴリズムの考え方は:GC Rootsと呼ばれるオブジェクトから検索を開始し、 オブジェクトがGC Rootsに参照チェーンで接続されていない場合、そのオブジェクトは 利用できません。Javaでは、以下のオブジェクトがGC Rootsとして使用できます。
- 仮想マシンスタックで参照されるオブジェクト
- メソッド領域クラスの静的プロパティによって参照されるオブジェクト
- メソッド領域定数プールによって参照されるオブジェクト
- ローカル・メソッド・スタック JNI参照オブジェクト
これらのアルゴリズムはオブジェクトが再利用可能かどうかを判断することができますが、上記の条件が満たされた場合、オブジェクトは必ずしも再利用されるわけではありません。オブジェクトがGC Rootによって到達可能でない場合、それは直ちに再利用されるのではなく、デッドロックフェーズに入り、真に再利用されるためには、2つのマークを通過する必要があります:オブジェクトが到達可能性分析でGC Rootへの参照の連鎖を持っていない場合、それは初めてマークされ、スクリーニングされ、スクリーニングはfinalize()メソッドの実行の必要性に基づいています。オブジェクトが finalize() メソッドをオーバーライドしていないか、または VM によってすでに呼び出されている場合、それは不要と見なされます。finalize()メソッドを実行する必要がある場合、オブジェクトはF-Queueと呼ばれるペアのキューに入れられ、VMはそれを実行するためにFinalize()スレッドをトリガします。これは優先度が低く、finalize()の実行が遅かったりデッドロックしたりすると、F-Queueがトリガされ、VMはその終了を待つことにコミットしません。これは、finalize()の実行が遅かったり、デッドロックが発生したりすると、F-Queueのキューが待機することになり、メモリ再生システムがクラッシュしてしまうからです。GCはF-Queueのオブジェクトに2回目のマークを付け、その時点でオブジェクトは「about to be reclaimed」セットから削除され、再生されるのを待ちます。
静的割り当てと動的割り当てとは何ですか?
静的代入メソッドの実行バージョンを見つけるために静的型に依存するすべての代入動作は静的代入と呼ばれ、その典型的な用途はメソッドのオーバーロードです。静的代入はコンパイル段階で行われるため、静的代入を決定する動作は実際には仮想マシンによって実行されません。
動的割り当て実際の型に基づいて、実行時にメソッドの実行バージョンを決定します。