Javaのガベージコレクションアルゴリズム(GC)

ガベージコレクションアルゴリズムとは

Javaプログラムを実行するプロセス全体で、関連するメモリが自動的に解放およびリサイクルされ、メモリリークが防止されます。これは、Java言語の重要な機能でもあります。したがって、どのメモリを再利用する必要があるか、いつ再利用する必要があるか、およびどのように再利用するか。これには、オブジェクトが生きているかどうかを判断するためのアルゴリズムを使用する必要があります。一般的に使用されるのは、参照カウント方法と到達可能性分析アルゴリズムですが、ガベージコレクションアルゴリズムはJavaで使用されるのは、マークスイープアルゴリズム、コピーアルゴリズム(コピー)、マークコンパクトアルゴリズム(マークコンパクト)、世代別収集アルゴリズムです。

カウント方法を紹介します

オブジェクトに参照カウンターを追加します。参照する場所がある場合は常に、カウンター値が1ずつ増加します。参照が無効な場合、カウンター値は1ずつ減少します。常にカウンターが0であるオブジェクトは再度使用することは不可能であり、オブジェクトをリサイクルすることができます。
利点:
参照カウントコレクターは非常に迅速に実行でき、プログラムの実行に織り交ぜられます。これは、プログラムを長時間中断しないようにする必要があるリアルタイム環境に役立ちます。
短所:
循環参照を検出できません。*親オブジェクトに子オブジェクトへの参照がある場合、子オブジェクトは次に親オブジェクトを参照します。このように、それらの参照カウントが0になることはありません。

参照カウントアルゴリズムでは、次のような循環参照の問題を解決できません。

public class Test{
		public Object instance=null;
		public statc void testGC(){
			Test A=new Test();
			Test B=new Test();
			A.instance=B;
			B.instance=A;
			A=null;
			B=null;
			System.gc();
		}
}

オブジェクトAとオブジェクトBの両方にフィー​​ルドインスタンスが割り当てられているため、A.instance = B、B.instance = Aに加えて、これら2つのオブジェクトには参照がなくなり、実際、これら2つのオブジェクトにアクセスできなくなります。それらは相互に参照しているため、参照カウントは0ではなく、リサイクルできません。

到達可能性分析アルゴリズム

ここに画像の説明を挿入
参照カウント法の循環参照問題を解決するために、Javaは到達可能性分析の方法を使用します。一連の「GCルート」を通じて、オブジェクトが開始点として検索されます。「GCルート」とオブジェクトの間に到達可能なパスがない場合、そのオブジェクトは到達不能であると言われます。到達不能なオブジェクトはリサイクル可能なオブジェクトと同等ではないことに注意してください。2つのマーキングプロセスがあります。2回マークを付けた後もリサイクル可能なオブジェクトである場合は、リサイクルに直面します

フラグスイープアルゴリズム

マーキングとクリアの2つのステージに分かれており、マーキングステージではリサイクルが必要なすべてのオブジェクトにマークを付け、クリアステージではマークされたオブジェクトが占めるスペースを再利用します。図に示すアルゴリズムの欠点は
ここに画像の説明を挿入
、効率が高くなく、フラグがクリアされた後に多数の不連続メモリフラグメントが生成されることです。制御フラグメントが多すぎると、より大きなオブジェクトを割り当てる必要がある場合に発生する可能性があります。プログラム実行プロセスでは、十分なメモリを見つけることができません。連続したメモリであり、事前に別のガベージコレクションアクションをトリガーする必要があります。

レプリケーションアルゴリズム

効率の問題を解決するために、使用可能なメモリは容量に応じて同じサイズの2つのブロックに分割され、一度に1つのブロックのみが使用されます。ブロックが使い果たされると、残りのオブジェクトが他のオブジェクトに割り当てられます。ブロックし、使用済みメモリスペースを一度にクリアします。
ここに画像の説明を挿入
このアルゴリズムは実装が簡単で、メモリ効率が高く、断片化の傾向がありませんが、最大の問題は、使用可能なメモリが元のメモリの半分に圧縮されること
です。また、存続しているオブジェクトが多い場合、コピーアルゴリズムの効率は大幅に低下します。

マーク照合アルゴリズム

マーキングプロセスは、マーキングクリーニングアルゴリズムと同じです。後続の手順では、リサイクル可能なオブジェクトを直接クリーンアップするのではなく、残っているすべてのオブジェクトを一方の端に移動してから、端の境界の外側でメモリを直接クリーンアップします。マーキング洗浄アルゴリズムの概略図は次のとおりです。

ここに画像の説明を挿入

世代別収集アルゴリズム

現在、商用仮想マシンのガベージコレクションは「世代別コレクション」アルゴリズムを採用しています。このアルゴリズムには新しいアイデアはありませんが、オブジェクトのライフサイクルごとにメモリをいくつかのブロックに分割します。一般に、Javaヒープは新世代と旧世代に分けられるため、各世代の特性に応じて最適な収集アルゴリズムを採用でき、残りのオブジェクトをわずかなコストでコピーして収集を完了できます。 。老後は、オブジェクトの生存率が高く、割り当てるスペースがないため、マークスイープまたはマークソートアルゴリズムを使用してリサイクルする必要があります。

知識ポイントの追加
GCの観点から、Javaヒープは次のように細分化することもできます:新世代(エデンエリア、サバイバーエリアからサバイバーエリアへ)と老後。
図に示すように
ここに画像の説明を挿入
、新世代:それ新しいオブジェクトを格納するために使用されます。通常、ヒープスペースの1/3を占めます。オブジェクトが頻繁に作成されるため、新世代はガベージコレクションのためにMinorGCを頻繁にトリガーします。新世代はさらに、Edenエリア、ServivorFrom、およびServivorToの3つのエリアに分割されます。
1.エデンエリア:Javaオブジェクトの発祥の地(新しく作成されたオブジェクトが大量のメモリを占有する場合、それは古い時代に直接割り当てられます)。Edenエリアのメモリが不足すると、MinorGCがトリガーされ、新しい世代のエリアでガベージコレクションが実行されます。
2.ServicorFrom:このGCのスキャンされた人物としての最後のGCの生存者。
3.ServivorTo:MinorGCプロセスのサバイバーを保持します。
4. MinorGCプロセス([コピー]->[クリア]->[スワップ]):最初に、EdenおよびServivorFromエリアの存続しているオブジェクトをServicorToエリアにコピーします(オブジェクトの年齢があり、古い年齢基準に達した場合は、それを古い年齢に割り当てますエリア)、同時にこれらのオブジェクトの年齢を1増やし(ServicorToが十分でない場合は、古いエリアに配置します)、EdenとServicorFromのオブジェクトをクリアします。最後に、ServicorToとServicorFromが交換され、元のオブジェクトが交換されます。 ServicorToは、次のGC
エリアのServicorFromになります。

古い世代
は、主にライフサイクルの長いメモリオブジェクトをアプリケーションに格納します。
古い時代のオブジェクトは比較的安定しているため、MajorGCは頻繁に実行されません。MinorGCは通常、MajorGCの前に実行されるため、新しい世代のオブジェクトは古い世代に入り、トリガーはスペースが十分でない場合にのみトリガーされます。新しく作成されたより大きなオブジェクトに割り当てるのに十分な大きさの連続したスペースが見つからない場合、ガベージコレクションがスペースを作成するためにMajorGCが事前にトリガーされます。
MajorGCは、マークアンドスイープアルゴリズムを使用します。最初にすべての古い世代をスキャンし、残っているオブジェクトにマークを付けてから、マークされていないオブジェクトをリサイクルします。MajorGCはスキャンしてリサイクルする必要があるため、時間がかかります。MajorGCはメモリの断片化を生成します。メモリの損失を減らすために、通常、次回直接割り当てるためにそれらをマージまたはマークする必要があります。老後が満杯で収まらない場合、OOM(メモリ不足)例外がスローされます。

新世代のメモリリカバリはレプリケーションアルゴリズムを採用しています
。新世代では、ほとんどのオブジェクトがガベージコレクションごとにリカバリされます。つまり、コピーされる操作は比較的少なくなりますが、新世代は通常1:1で分割されません。一般的に、新世代は大きなエデンスペースと2つの小さなサバイバースペース(スペースからスペースへ)に分けられます。エデンスペースとサバイバースペースの1つが使用されるたびに、リサイクル時に2つのスペースが使用されます。オブジェクトは別のサバイバースペースにコピーされます。図に示すように、
ここに画像の説明を挿入
老後の記憶回復はマークソートアルゴリズムを採用しています

  1. JAVA仮想マシンによって言及されたメソッド領域のPermanentGeneration(Permanet Generation)は、クラス定数、メソッドの説明などを格納するために使用されます。永遠の世代のコレクションには、主に破棄された定数と役に立たないクラスが含まれます。
  2. オブジェクトのメモリ割り当ては、主に新世代のエデンスペースとサバイバースペースのフロムスペース(サバイバーの前にオブジェクトが保存されている部分)にあり、場合によっては、古いものに直接割り当てられます。世代。
  3. 新世代のエデンスペースとフロムスペースが不足している場合、GCが発生します。GC後、エデンスペースとフロムスペースエリアの生き残ったオブジェクトは、Toスペースに移動され、次にエデンスペースとフロムスペースに移動されます。クリーンアップされます。
  4. To Spaceがオブジェクトを格納するのに十分でない場合、オブジェクトは古い世代に格納されます。
  5. GCの後、EdenSpaceやToSpaceなどが使用されます。6.オブジェクトがサバイバーエリアのGCを脱出すると、その年齢は+1になります。15歳のオブジェクトは、デフォルトで古い世代に移動されます。

ガベージコレクションの永続生成マーキング終了アルゴリズム
Java仮想マシンのメモリ内のメソッド領域は、Sun HotSpot仮想マシンの永続生成と呼ばれます。これは、各スレッドによって共有されるメモリ領域であり、次のクラス情報を格納するために使用されます。仮想マシンによってロードされます。定数、静的変数、ジャストインタイムでコンパイルされたコードおよびその他のデータ。永続生成のガベージコレクションは効率が低く、効率も低くなりますが、ガベージコレクションも行う必要があります。そうしないと、永続生成メモリが十分でない場合でもOutOfMemoryError例外がスローされます。

要約:前述のように、Javaの一般的なガベージコレクションアルゴリズムを理解しています。調査されるまでにさらに詳細な待機があり、機能が制限されている可能性があります。いくつかのブログ記事を読んだ後、これを結論付けました。これはより便利な場合があります。将来を振り返る。

参照は次のとおりです。
[1]:https
://www.cnblogs.com/huajiezh/p/5769255.html [2]:「Javaコアナレッジポイント」
[3]:「Java仮想マシンの詳細な理解JVMの高度な機能と最もベストプラクティス

おすすめ

転載: blog.csdn.net/cjy_win/article/details/88681434