ガベージ コレクション アルゴリズムと JVM ガベージ コレクターの概要

ガベージ コレクション アルゴリズムと JVM ガベージ コレクターの概要

[[199042]]

ガベージ コレクション アルゴリズムと JVM ガベージ コレクターの概要は、著者の JVM 内部原理とパフォーマンス チューニングに関する一連の記事にまとめられています。記事内の参考資料については、Java 学習および実践資料インデックスと JVM 資料インデックスを参照してください。

よく話題になるガベージ コレクション アルゴリズムは、オブジェクト検索アルゴリズムと実際のリサイクル方法の 2 つの部分に分けられます。コレクターによって実装の詳細は異なりますが、一般的に、ほとんどすべてのコレクターは、すべてのライブ オブジェクトの検索と、その他のすべてのオブジェクト (つまり、放棄されたオブジェクトまたは役に立たないオブジェクト) のクリーンアップという 2 つの側面に重点を置いています。 Java 仮想マシン仕様では、ガベージ コレクターの実装方法は指定されていません。そのため、異なるメーカーや異なるバージョンの仮想マシンが提供するガベージ コレクターは大きく異なる可能性があり、一般的には、ユーザーが独自のアプリケーション特性と要件に応じて、異なる時代のコレクターを組み合わせるためのパラメーターが提供されます。最も主流の 4 つのガベージ コレクターは、シリアル GC、スループット/パラレル GC、CMS GC、および G1 GC であり、通常は単一 CPU 環境で使用されます。

ガベージ コレクターについて議論する場合、並列と同時実行、マイナー GC とメジャー/フル GC など、多くの概念が関係してくることがよくあります。並列処理とは、複数のガベージ コレクション スレッドが並行して動作するものの、ユーザー スレッドは待機状態のままであることを意味します。同時実行とは、ユーザー スレッドとガベージ コレクション スレッドが同時に実行され (必ずしも並行して実行される必要はなく、交互に実行される場合もあります)、ユーザー プログラムは実行を継続し、ガベージ コレクション プログラムは別の CPU で実行されることを意味します。マイナー GC は、新しい世代で発生するガベージ コレクション アクションを指します。ほとんどの Java オブジェクトはすぐに生成されて消滅するため、マイナー GC は非常に頻繁に発生し、回復速度は一般に高速です。メジャー GC は、古い世代で発生する GC を指します。メジャー GC の発生には、少なくとも 1 つのマイナー GC が伴うことがよくあります (ただし、必ず伴うわけではありません。Parallel Scavenge コレクターのコレクション ストラテジーは、メジャー GC のストラテジーを直接選択します)。メジャー GC の速度は、一般にマイナー GC の 10 倍以上遅くなります。ガベージ コレクターをさまざまな観点から分析すると、さまざまなタイプに分類できます。

ガベージ コレクターを評価するために最も一般的に使用される指標は、スループットと一時停止時間です。一時停止時間が短いほど、ユーザーと対話する必要があるプログラムに適しています。応答速度が速いと、ユーザー エクスペリエンスが向上します。スループットが高いと、CPU 時間を最大限に活用し、プログラムの計算タスクをできるだけ早く完了できます。これは主に、バックグラウンドで実行され、多くの対話を必要としないタスクに適しています。具体的な指標は次のとおりです。

  • スループット: アプリケーションのライフサイクル中にアプリケーションが費やした時間とシステムの合計実行時間の比率を指します。システムの合計実行時間 = アプリケーション時間 + GC 時間。システムが 100 分間実行され、GC に 1 分かかる場合、システム スループットは (100-1)/100 = 99% になります。
  • ガベージ コレクターの負荷: スループットとは対照的に、ガベージ コレクターの負荷は、システムの実行時間の合計に対するコレクターで費やされた時間の比率を指します。
  • 一時停止時間: ガベージ コレクターの実行中にアプリケーションが一時停止される時間を指します。限定コレクターの場合、一時停止時間が長くなる場合があります。並行コレクターを使用すると、ガベージ コレクターとアプリケーションが交互に実行されるため、プログラムの停止時間が短くなります。ただし、排他的ガベージ コレクターよりも効率が低くなる可能性があるため、システムのスループットが低下する可能性があります。
  • ガベージ コレクションの頻度: ガベージ コレクターが実行される頻度を示します。一般的に、固定アプリケーションの場合、ガベージ コレクターの頻度は可能な限り低くする必要があります。一般的に、ヒープ領域を増やすと、ガベージ コレクションの頻度を効果的に減らすことができますが、コレクションによって発生する一時停止時間が長くなる可能性があります。
  • 反応時間: オブジェクトがガベージと呼ばれた後、そのオブジェクトが占有していたメモリ領域が解放されるまでにかかる時間を指します。
  • ヒープ割り当て: ガベージ コレクターによってヒープ メモリの割り当て方法が異なる場合があります。優れたガベージ コレクターには、適切なヒープ メモリ範囲の分割が必要です。

オブジェクト検索アルゴリズムの助けを借りれば、使用できるメモリを見つけたり、そのメモリを再利用したりできます。多くの場合、同じ目標を達成するために、より少ない労力で済ませる用意があることは間違いありません。

オブジェクト参照

JDK 1.2 より前のバージョンでは、オブジェクトがどの変数からも参照されていない場合、プログラムはそのオブジェクトを使用できなくなりました。つまり、プログラムはオブジェクトが Reachable 状態にある場合にのみそのオブジェクトを使用できます。 JDK 1.2 以降では、オブジェクト参照が 4 つのレベルに分割され、プログラムはオブジェクトのライフ サイクルをより柔軟に制御できるようになりました。これらの 4 つのレベルは、高から低の順に、強参照、ソフト参照、弱参照、ファントム参照です。

StrongReference: 強い参照

強参照は最も一般的に使用される参照です。オブジェクトに強い参照がある場合、ガベージ コレクターはそれを回収しません。メモリ領域が不足している場合、Java 仮想マシンは、強い参照を持つオブジェクトを任意に再利用してメモリ不足の問題を解決するのではなく、OutOfMemoryError エラーをスローしてプログラムを異常終了させます。たとえば、次のコード:

  1. パブリッククラスMain {
  2. 公共 静的void main(String[] args) {
  3. 新しい Main().fun1();
  4. }
  5.  
  6. パブリックvoid fun1() {
  7. オブジェクトオブジェクト = new Object();
  8. オブジェクト[] objArr = 新しいオブジェクト[1000];
  9. }
  10. }

Object[] objArr = new Object[1000]; という文を実行するときにメモリが不足すると、JVM は OOM エラーをスローし、object が指すオブジェクトをリサイクルしません。ただし、fun1 の実行が終了すると、object と objArr は存在しなくなるため、それらが指すオブジェクトは JVM によってリサイクルされることに注意してください。強い参照とオブジェクト間の関連付けを解除したい場合は、参照を明示的に null に割り当てることができます。このようにして、JVM は適切なタイミングでオブジェクトを再利用します。たとえば、Vector クラスの clear メソッドは、参照を null に割り当てることでクリーンアップを実行します。

  1. /**
  2. *このベクター内の指定された位置にある要素を削除します。
  3. *後続の要素シフトます
  4. * インデックス)。ベクターから削除された要素を返します
  5. *
  6. *インデックス   範囲
  7. * ({@codeインデックス< 0 ||インデックス>=サイズ()})
  8. * @param indexインデックス 削除する要素
  9. * @return削除された要素
  10. * @1.2 以降
  11. */
  12. パブリック同期E削除( int  索引) {
  13. modCount++;
  14. if (インデックス>= 要素数 )
  15. 新しいArrayIndexOutOfBoundsException(インデックス)をスローします。
  16. オブジェクト oldValue = elementData[インデックス];
  17.  
  18. int numMoved = 要素数 -インデックス- 1;
  19. (移動数>0)の場合
  20. System.arraycopy(要素データ、インデックス+1、要素データ、インデックス
  21. 移動した数);
  22. elementData[ --elementCount] = null; // gc に任せる 
  23.  
  24. (E)oldValueを返します
  25. }

SoftReference: ソフト参照

ソフト参照は、役に立つが必須ではないオブジェクトを記述するために使用され、Java では java.lang.ref.SoftReference クラスによって表されます。ソフト参照に関連付けられたオブジェクトの場合、JVM はメモリが不足している場合にのみオブジェクトを再利用します。したがって、これを使用すると OOM の問題を非常にうまく解決でき、この機能は Web ページのキャッシュ、画像のキャッシュなどのキャッシュの実装に非常に適しています。ソフト参照は、参照キュー (ReferenceQueue) と組み合わせて使用​​できます。ソフト参照によって参照されるオブジェクトが JVM によって再利用されると、ソフト参照はそれに関連付けられた参照キューに追加されます。使用例は次のとおりです。

  1. java.lang.ref.SoftReference をインポートします。
  2.  
  3. パブリッククラスMain {
  4. 公共 静的void main(String[] args) {
  5.  
  6. SoftReference<String> sr = new SoftReference<String>(新しい文字列( "hello" ));
  7. System.out.println (sr.get()) ;
  8. }
  9. }

WeakReference: 弱参照

弱参照とソフト参照の違いは、弱参照のみを持つオブジェクトのライフ サイクルは短くなることです。ガベージ コレクター スレッドが管轄下のメモリ領域をスキャンすると、弱参照のみを持つオブジェクトが見つかると、現在のメモリ領域が十分かどうかに関係なく、そのメモリが再利用されます。ただし、ガベージ コレクターは優先度の低いスレッドであるため、弱い参照のみを持つオブジェクトをすぐに検出できない可能性があります。

  1. java.lang.ref.WeakReference をインポートします。
  2.  
  3. パブリッククラスMain {
  4. 公共 静的void main(String[] args) {
  5.  
  6. WeakReference<String> sr = new WeakReference<String>(new String( "hello" ));
  7.  
  8. System.out.println (sr.get()) ;
  9. System.gc(); //JVM の gc にガベージコレクションを実行するよう通知する
  10. System.out.println (sr.get()) ;
  11. }
  12. }

出力は次のようになります。

  1. こんにちは
  2. ヌル 

2 番目の出力結果は null です。これは、JVM がガベージ コレクションを実行している限り、弱参照に関連付けられたオブジェクトがリサイクルされることを意味します。ただし、ここで弱参照に関連付けられたオブジェクトは、弱参照によってのみ関連付けられたオブジェクトを参照することに注意してください。同時に強参照が関連付けられている場合、オブジェクトはガベージコレクション時にリサイクルされません(ソフト参照の場合も同様です)。弱参照は、参照キュー (ReferenceQueue) と組み合わせて使用​​できます。弱参照によって参照されるオブジェクトがガベージ コレクションされると、Java 仮想マシンは、関連付けられている参照キューに弱参照を追加します。

PhantomReference: ファントムリファレンス

名前が示すように、「ファントム参照」は意味がありません。他の種類の参照とは異なり、ファントム参照はオブジェクトのライフサイクルを決定しません。オブジェクトがファントム参照のみを保持している場合、参照がまったくない場合と同じになり、いつでもガベージ コレクターによって回収される可能性があります。以前のソフト参照や弱参照とは異なり、仮想参照はオブジェクトのライフ サイクルに影響を与えません。 Java では、java.lang.ref.PhantomReference クラスによって表されます。オブジェクトがファントム参照に関連付けられている場合は、そのオブジェクトには参照が関連付けられていないのと同じであり、いつでもガベージ コレクターによって回収される可能性があります。ファントム参照は参照キューと組み合わせて使用​​する必要があることに注意してください。ガベージ コレクターがオブジェクトをリサイクルする準備ができたときに、そのオブジェクトにまだファントム参照が残っていることが判明した場合、ガベージ コレクターはこのファントム参照をそれに関連付けられた参照キューに追加します。プログラムは、ファントム参照が参照キューに追加されたかどうかを判断することによって、参照されたオブジェクトがガベージ コレクションされるかどうかを判断できます。プログラムは、ファントム参照が参照キューに追加されたことを検出した場合、参照されたオブジェクトのメモリが再利用される前に必要なアクションを実行できます。

  1. java.lang.ref.PhantomReference をインポートします。
  2. java.lang.ref.ReferenceQueue をインポートします。
  3.  
  4.  
  5. パブリッククラスMain {
  6. 公共 静的void main(String[] args) {
  7. ReferenceQueue<String> キュー = 新しい ReferenceQueue<String>();
  8. PhantomReference<String> pr = new PhantomReference<String>(new String( "hello" ), queue);
  9. System.out.println (pr.get()) ;
  10. }
  11. }

物体生存判定

オブジェクトの実行可能性を判断する一般的な方法には、参照カウントと到達可能性分析があります。ただし、参照カウントでは循環オブジェクト参照の問題を解決できないため、主流の JVM では到達可能性分析が使用される傾向があります。

参照カウント:

参照カウンターは、Microsoft の COM コンポーネント テクノロジと Adob​​e の ActionScript で使用されます。参照カウンタの原理は非常に単純です。オブジェクト A の場合、いずれかのオブジェクトが A を参照している限り、A の参照カウンタは 1 増加します。参照が無効な場合、参照カウンタは 1 減少します。オブジェクト A の参照カウンタの値が 0 である限り、オブジェクト A は使用できなくなります。参照カウンターの実装も非常に簡単です。オブジェクトごとに整数カウンターを構成するだけです。しかし、参照カウンターには重大な問題があります。それは、循環参照を処理できないことです。したがって、このアルゴリズムは Java のガベージ コレクターでは使用されません。単純な循環参照の問題は、次のように説明されます。オブジェクト A と B があり、オブジェクト A にはオブジェクト B への参照が含まれ、オブジェクト B にはオブジェクト A への参照が含まれます。この時点では、オブジェクト A とオブジェクト B の両方の参照カウンタは 0 ではありません。ただし、システム内に A または B を参照する 3 番目のオブジェクトは存在しません。つまり、A と B はリサイクルされるべきガベージ オブジェクトですが、ガベージ オブジェクトが相互に参照しているため、ガベージ コレクターはそれらを認識できず、メモリ リークが発生します。

参照ツリーのトラバーサル

いわゆる参照ツリーは、本質的にはルート付きグラフ構造です。オブジェクトのルート ハンドルに沿って下方向に検索し、ライブ ノードを見つけてマークします。マークされていない残りのノードはデッド ノードです。これらのオブジェクトはリサイクルするか、ライブ ノードをコピーして削除することができます。具体的な詳細は、HeapSize の領域とアルゴリズムによって異なります。一般的な概略図を下の図に示します (ここではポインターが一方向であることに注意してください)。

まず、すべての収集家は、残っている物体を数えるマーキングのプロセスを実行します。 JVM で使用される最新の GC アルゴリズムはすべて、まずすべてのライブ オブジェクトを検出してから収集します。次の図に示す JVM のメモリ レイアウトを使用すると、この概念がよくわかります。

いわゆる GC ルート オブジェクトには、現在実行されているメソッド内のすべてのローカル変数と入力パラメーター、アクティブなスレッド、ロードされたクラス内の静的変数、および JNI 参照が含まれます。次に、ガベージ コレクターは、GC ルート オブジェクトから始めて、インスタンス変数などのルート オブジェクトによって参照される他のオブジェクトまで、メモリ内のオブジェクト グラフ全体を走査します。コレクターは、アクセスしたすべてのオブジェクトをライブとしてマークします。上の図では、ライブ オブジェクトは青色でマークされています。マーキングフェーズが完了すると、すべてのライブオブジェクトがマークされます。その他 (上図の灰色のもの) は、GC ルートからアクセスできないオブジェクトであり、アプリケーションでは使用されなくなります。これらはガベージ オブジェクトであり、コレクターは次のフェーズでこれらをクリアします。

ただし、GC ルートに到達できないことが判明したオブジェクトは、すぐには再利用されません。実際に再利用される前に、オブジェクトは少なくとも 2 回マークされる必要があります。オブジェクトが初めて到達不能であると判明すると、そのオブジェクトは一度マークされ、このオブジェクトの finalize() メソッド (存在する場合) が呼び出されます。2 回目に到達不能であると判明すると、そのオブジェクトはリサイクルされます。 finalisze() メソッドを使用すると、オブジェクトはリサイクルされる運命から一度だけ逃れることができます。エスケープ方法は次のとおりです。finalize() メソッドで、GCRoots に自分自身へのフックを追加する必要があります。

  1. パブリッククラスEscapeFromGC(){
  2. 公共 静的EscapeFromGC フック;
  3. @オーバーライド
  4. 保護されたvoid finalize()はThrowableをスローします{
  5. super.finalize();
  6. System.out.println ( "finalizeメソッドが実行されました!" );
  7. EscapeFromGC.hook = これ;
  8. }

一般的なガベージコレクションアルゴリズム

マークスイープ: マークスイープアルゴリズム

マークスイープ アルゴリズムは、ガベージ コレクションをマーキング フェーズとスイープ フェーズの 2 つのフェーズに分割します。 1 つの可能な実装は、マーキング フェーズ中に最初にルート ノードを通過し、ルート ノードから始まるすべての大きなオブジェクトをマークすることです。したがって、マークされていないオブジェクトは参照されていないガベージ オブジェクトです。次に、クリーンアップ フェーズで、マークされていないオブジェクトがすべてクリアされます。このアルゴリズムの最大の問題は、再利用されたスペースが不連続であるため、スペースの断片化が多発することです。オブジェクトにヒープ領域を割り当てるプロセス、特に大きなオブジェクトのメモリ割り当てでは、不連続なメモリ領域の効率は連続した領域よりも低くなります。

概念的には、マーク アンド スイープ アルゴリズムで使用されるアプローチは、これらのオブジェクトを単に無視するだけなので、最も単純です。つまり、マーキング フェーズが完了すると、アクセスされていないオブジェクトが配置されているスペースは空きであるとみなされ、新しいオブジェクトの作成に使用できるようになります。この方法では、すべての空き領域とそのサイズを記録するために空きリストを使用する必要があります。フリーリストの管理により、オブジェクトを割り当てる際の作業負荷が増加します。この方法にも欠点があります。空き領域のサイズは十分であっても、この割り当てに必要なサイズを満たす領域が 1 つも存在しない可能性があるため、この割り当ては失敗します (Java では OutOfMemoryError になります)。

コピー: コピーアルゴリズム

既存のメモリ空間を 2 つのブロックに分割し、一度に 1 つのみを使用します。ガベージ コレクション中は、使用中のメモリ内の生き残ったオブジェクトが未使用のメモリ ブロックにコピーされます。その後、使用中のメモリ ブロック内のすべてのオブジェクトがクリアされ、2 つのメモリの役割が入れ替わり、ガベージ コレクションが完了します。システム内にガベージ オブジェクトが多数存在する場合、レプリケーション アルゴリズムがレプリケートする必要があるライブ オブジェクトの数はそれほど多くありません。したがって、ガベージ コレクションが本当に必要な場合、コピー アルゴリズムは非常に効率的です。ガベージ コレクション プロセス中にオブジェクトが新しいメモリ領域に均一にコピーされるため、リサイクル後のメモリ領域にフラグメントがないことが保証されます。このアルゴリズムの欠点は、システム メモリが半分に削減されることです。

コピー アルゴリズムのアイデアは、Java の新世代シリアル ガベージ コレクターで使用されています。新世代は、エデン スペース、フロム スペース、トゥ スペースの 3 つの部分に分かれています。 from スペースと to スペースは、レプリケーションに使用される同じサイズ、同じステータス、役割を交換できる 2 つのスペース ブロックと見なすことができます。 from スペースと to スペースは、survivor スペースとも呼ばれ、リサイクルされていないオブジェクトを格納するために使用されます。ガベージ コレクション中、Eden スペース内の残存オブジェクトは未使用の Survivor スペース (to であると想定) にコピーされ、使用中の Survivor スペース (from であると想定) 内の若いオブジェクトも to スペースにコピーされます (大きなオブジェクトまたは古いオブジェクトは古いバンドに直接移動します。to スペースがいっぱいの場合、オブジェクトも古い世代に直接移動します)。この時点で、eden スペースと from スペースに残っているオブジェクトはガベージ オブジェクトであり、直接クリアすることができ、to スペースにはこのリサイクル後に残ったオブジェクトが格納されます。この改良されたレプリケーション アルゴリズムは、スペースの連続性を保証するだけでなく、メモリ スペースの無駄を大幅に回避します。

マーク コピー アルゴリズムは、残っているすべてのオブジェクトを再割り当てするという点で、マーク コンパクト アルゴリズムと非常によく似ています。違いは、再割り当て先のアドレスが異なることです。コピー アルゴリズムは、生き残ったオブジェクトの新しいホームとして別のメモリ領域を割り当てます。マーク コピー アルゴリズムの利点は、マーキング フェーズとコピー フェーズを同時に実行できることです。欠点は、生き残ったすべてのオブジェクトを収容するために追加のメモリ領域が必要になることです。

マークコンパクト: マーク圧縮アルゴリズム

レプリケーション アルゴリズムの効率は、ライブ オブジェクトが少なく、ガベージ オブジェクトが多いという前提に基づいています。これは若い世代では頻繁に発生しますが、ほとんどのオブジェクトがライブである古い世代ではより一般的です。レプリケーション アルゴリズムを引き続き使用すると、残存するオブジェクトの数が多いため、レプリケーションのコストが非常に高くなります。

マーク圧縮アルゴリズムは、マークスイープアルゴリズムに基づいていくつかの最適化を行う旧世代のリサイクルアルゴリズムです。また、最初にルート ノードから始めて、到達可能なすべてのオブジェクトをマークする必要がありますが、その後、マークされていないオブジェクトを単にクリーンアップするのではなく、残っているすべてのオブジェクトをメモリの一方の端に圧縮します。その後、境界線の外側のスペースをすべてクリアします。この方法は、断片化の発生を回避し、2 つの同一のメモリ空間を必要としないため、コスト効率が高くなります。

マーク コンパクト アルゴリズムは、マーク スイープ アルゴリズムの欠点を修正し、マークされたすべてのライブ オブジェクトをメモリ領域の先頭に移動します。このアプローチの欠点は、すべてのオブジェクトを新しい場所にコピーし、参照アドレスを更新する必要があるため、GC 一時停止時間が長くなることです。マーク アンド スイープ アルゴリズムと比較すると、その利点も明らかです。ソート後、新しいオブジェクトの割り当てはポインタ バンピングのみで完了できるため、非常に簡単です。この方法を使用すると、空き領域の場所が常にわかるため、断片化の問題は発生しなくなります。

増分収集:

ガベージ コレクション プロセス中、アプリケーション ソフトウェアは CPU 消費量が高い状態になります。この CPU 消費量が多い状態では、アプリケーションのすべてのスレッドが中断され、すべての通常の作業が中断され、ガベージ コレクションが完了するまで待機します。ガベージコレクションの時間が長すぎると、アプリケーションが長時間停止し、ユーザーエクスペリエンスやシステムの安定性に重大な影響を与えます。

インクリメンタル アルゴリズムは、現代のガベージ コレクションの前身です。その基本的な考え方は、すべてのガベージを一度に処理すると、システムが長時間停止し、ガベージ コレクション スレッドとアプリケーション スレッドを交互に実行できるというものです。毎回、ガベージ コレクション スレッドはメモリ空間の小さな領域のみを収集し、その後アプリケーション スレッドに切り替えます。ガベージコレクションが完了するまでこのプロセスを繰り返します。この方法を使用すると、ガベージ コレクション プロセス中にアプリケーション コードが断続的に実行されるため、システムの一時停止時間を短縮できます。ただし、スレッド切り替えとコンテキスト切り替えの消費により、ガベージ コレクションの全体的なコストが増加し、システムのスループットが低下します。

世代別収集: 世代別収集アルゴリズム

世代別コレクターは、増分コレクションの別の具体化です。ガベージ コレクション オブジェクトの特性に応じて、さまざまな段階での最善の方法は、この段階でのガベージ コレクションに適したアルゴリズムを使用することです。世代別アルゴリズムはこのアイデアに基づいています。オブジェクトの特性に応じてメモリ間隔をいくつかのブロックに分割し、各メモリ間隔の特性に応じて異なるコレクション アルゴリズムを使用して、ガベージ コレクションの効率を向上させます。ホットスポット仮想マシンを例にとると、新しく作成されたすべてのオブジェクトは、若い世代と呼ばれるメモリ領域に配置されます。若い世代の特徴は、オブジェクトがすぐにリサイクルされることです。そのため、若い世代ではより効率的なレプリケーション アルゴリズムが選択されます。オブジェクトが複数のコレクションを生き残る場合、古い世代と呼ばれるメモリ領域に配置されます。古い世代では、ほぼすべてのオブジェクトが複数のガベージ コレクションを生き残ります。したがって、これらのオブジェクトは一定期間、あるいはアプリケーションのライフサイクル全体にわたってメモリ内に常駐すると想定できます。コピー アルゴリズムを使用して古い世代を再利用する場合は、大量のオブジェクトをコピーする必要があります。さらに、旧世代のリサイクル費用対効果は新世代よりも低いため、このアプローチはお勧めできません。世代の考え方に基づいて、新しい世代とは異なるマーク圧縮アルゴリズムを古い世代のリサイクルに使用して、ガベージコレクションの効率を向上させることができます。

並行収集: 並行収集アルゴリズム

いわゆるリサイクルアルゴリズムと、アプリケーションが交互に動作することを意味しますが、時間は非常に短いです。生きている必要があるので、別の時間は圧縮されますが、GCは必ずしも古い世代では使用されていません。ここで使用できます)、そしてマーキングが完了した後、新しいメモリアプリケーションと放棄が存在する可能性があります(Java自体はメモリリリースの概念を持っていません)、JVMはこのプロセスで増分情報を記録します。したがって、この期間中のその増加は一般に非常に少なく、上記のようにリリースされる可能性はありません(JVMが完全にキャッシュしていない場合、JVMが自然に及ぼす可能性を緩和するのは適切ではありません)。一定の期間、つまり、指定された時間範囲内でリサイクルできない場合は、一定の期間になります。リサイクルを開始する前にメモリは10%未満です。同時リサイクルは、リサイクル中に割り当てを許可するため、同時リサイクル中、JVMは古い世代のGCを約68%で開始する可能性があります。

JVM ガベージ コレクターの比較

1999年にJDK1.3.1に初のガベージコレクターであるシリアルGCが搭載され、その後JDK1.4やJ2SE1.3が次々とリリースされました。 2002 年 2 月 26 日に J2SE1.4 がリリースされ、JDK1.4.2 とともに Parallel GC と Concurrent Mark Sweep (CMS) GC がリリースされ、JDK6 以降では Parallel GC が HotSpot のデフォルト GC になりました。これら 3 つのガベージ コレクターにもそれぞれ利点があります。シリアル GC はメモリ使用量と並列オーバーヘッドを最小限に抑えるシナリオに適しており、パラレル GC はアプリケーションのスループットを最大化するシナリオに適しており、CMS GC は中断や一時停止時間を最小限に抑えるシナリオに適しています。上図は、各種ガベージコレクターの関係を示したものです。しかし、アプリケーションが扱う業務が大規模化・複雑化し、ユーザー数も増えてくると、適切なコレクターがないとアプリケーションの正常な動作が保証できなくなり、また、STW の一時停止を頻繁に引き起こすコレクターでは実際の需要に追いつけなくなるため、コレクターの最適化を継続的に図っていきます。ガベージ ファースト (G1) GC は、このビジネス上の要求を満たすために生まれました。これは、ヒープ メモリを多数の無関係な領域に分割する並列コレクターです。各領域は、古い世代または若い世代に属することができ、各世代領域は物理的に不連続になる場合があります。

マーキングフェーズに関して注目すべき重要なポイントがいくつかあります。

  • マーキングを開始する前に、アプリケーション スレッドを一時停止する必要があります。そうしないと、オブジェクト グラフが絶えず変化している場合、実際にそれをトラバースできなくなります。 JVM が処理を実行できるようにアプリケーション スレッドが一時停止されるこの状況はセーフ ポイントと呼ばれ、Stop The World (STW) 一時停止をトリガーします。セーフ ポイントをトリガーする理由は多数ありますが、最も一般的な理由はおそらくガベージ コレクションです。
  • 一時停止の長さは、ヒープ内のオブジェクトの数やヒープ サイズではなく、ライブ オブジェクトの数によって決まります。したがって、ヒープ サイズを大きくしても、マーキング フェーズの長さには影響しません。

マーキング フェーズが完了すると、GC は次のフェーズを開始し、到達不可能なオブジェクトを削除します。

シリアルGC

シリアル コレクターには、2 つの主な特徴があります。1 つ目は、ガベージ コレクションに 1 つのスレッドのみを使用すること、2 つ目は、排他的なガベージ コレクターであることです。シリアル コレクターがガベージ コレクションを実行する場合、Java アプリケーション内のすべてのスレッドを一時停止してガベージ コレクションの完了を待機する必要があり、その結果、ユーザー エクスペリエンスが低下します。それにもかかわらず、シリアル コレクターは、長期間にわたって実稼働環境でテストされてきた、成熟した非常に効率的なコレクターです。新世代のシリアル プロセッサでは、実装が比較的簡単で、ロジック処理が非常に効率的で、スレッド切り替えのオーバーヘッドがないレプリケーション アルゴリズムが使用されています。単一の CPU プロセッサや小さなアプリケーション メモリなど、ハードウェア プラットフォームが特に有利ではない状況では、そのパフォーマンスは並列コレクターや同時コレクターのパフォーマンスを上回ることがあります。 HotSpot 仮想マシンでは、-XX:+UseSerialGC パラメータを使用して、新世代のシリアル コレクターと旧世代のシリアル コレクターの使用を指定します。これは、JVM がクライアント モードで実行されている場合のデフォルトのガベージ コレクターです。旧世代のシリアルコレクターはマーク圧縮アルゴリズムを使用します。新世代のシリアル コレクターと同様に、シリアル専用のガベージ コレクターでもあります。通常、旧世代のガベージ コレクションは新世代のガベージ コレクションよりも時間がかかるため、ヒープ領域が大きいアプリケーションでは、旧世代のシリアル コレクターが起動すると、アプリケーションが数秒以上停止する可能性があります。ただし、旧世代のシリアル コレクターは、さまざまな新世代のコレクターと組み合わせて使用​​することができ、CMS コレクターのバックアップ コレクターとしても機能します。旧世代のシリアル コレクターを有効にするには、次のパラメータを使用してみてください: -XX:+UseSerialGC: 新世代と旧世代の両方でシリアル コレクターが使用されます。

シリアル GC の動作手順は次のとおりです。

パーニューGC

パラレル コレクターは、新しい世代で動作するガベージ コレクターです。これは、シリアル コレクターを単純にマルチスレッド化したものです。リサイクル戦略、アルゴリズム、およびパラメータは、シリアルコレクターのものと同じです。

並列コレクターは排他コレクターでもあります。コレクション プロセス中は、アプリケーション全体が一時停止されます。ただし、パラレルコレクターはガベージコレクションに複数のスレッドを使用しているため、単一のCPUまたは弱い並行性を備えたCPUのシリアルコレクターの一時停止時間は、平行コレクターの効果がより良くなります。パラレルコレクターを有効にするには、パラメーター-XX:+UseParnewGCを使用できます。古い世代の並列リサイクルコレクターは、マルチスレッドの同時コレクターでもあります。 New Generation Parallel Collectorのように、スループットに焦点を当てたコレクターでもあります。古い世代の平行コレクターは、JDK1.6の後に有効になったマーク圧縮アルゴリズムを使用します。

平行GC

並列スカベンジコレクターの特徴は、その焦点が他のコレクターとは異なることです。 Parallel Oldは、マルチスレッドと「マークスイープ」アルゴリズムを使用するParallel Scavenge Collectorの古い世代バージョンです。このコレクターは、JDK 1.6でのみ利用可能でした。 -xx:+parallelloldgcは、新世代と古い世代の両方でパラレルコレクションコレクターを使用します。パラメーター-xx:Parallelgcthreadsを使用して、ガベージコレクションのスレッド数を設定することもできます。

並列GCの作業手順は次のとおりです。

CMS GC

CMS(同時マークスイープ)は、スループットを犠牲にして最短のコレクションの一時停止時間を達成するゴミコレクターです。 CMS GCはマークスイープアルゴリズムを使用するため、CMSによって収集されたヒープは、ヒープスペース廃棄物の問題を解決するために、スペースの断片化を生成します。代わりに、いくつかの未割り当てのスペースがリストに集約されます。JVMがオブジェクトスペースを割り当てると、このリストを検索して、オブジェクトを保存するのに十分な大きさのスペースを見つけます。一方、CMSスレッドとアプリケーションスレッドが同時に実行されるため、CMS GCはより多くのCPUリソースを必要とします。同時に、CMSマーキングフェーズ中にアプリケーションのスレッドがまだ実行されているため、CMSがヒープを回収する前に、実行中のアプリケーションに割り当てられるように、ヒープスペースが引き続き割り当てられます。言い換えれば、古い世代がいっぱいになったときにCMSは収集を開始しません。代わりに、上記の状況を避けるために、コレクションを早めに開始しようとします。デフォルトでは、コレクションが完了する前に割り当てるのに十分なスペースがありません。 - xx:cmsinitiatingoccupancyfraction = nこのしきい値を設定します。

CMS GCの作業手順は次のとおりです。

  • 初期マーク(STW初期マーク):この段階では、仮想マシンは実行中のタスクを一時停止する必要があります(単語を停止します)。このプロセスは、ガベージコレクションの「ルートオブジェクト」から始まり、「ルートオブジェクト」に直接関連付けることができるオブジェクトのみをスキャンおよびマークします。したがって、このプロセスはJVM全体を一時停止しますが、非常に迅速に完了します。
  • 同時マーキング:このフェーズは、初期マーキングフェーズに従い、初期マーキングに基づいてマーキングを下方に追跡し続けます。同時マーキングフェーズでは、アプリケーションのスレッドと同時マーキングスレッドが同時に実行されるため、ユーザーは一時停止を感じません。
  • 同時の先入観:同時の先入観段階は依然として同時にあります。このフェーズでは、仮想マシンは、同時マーキングフェーズ中に古い世代に新たに入ったオブジェクトを検索します(一部のオブジェクトは、新世代から古い世代に宣伝されるか、一部のオブジェクトが古い世代に割り当てられる場合があります)。次の段階が世界を止めるため、次の段階での「再マーク」作業が削減されます。
  • 備考(STWの備考):このフェーズは仮想マシンを一時停止し、コレクタースレッドはCMSヒープ内の残りのオブジェクトをスキャンします。スキャンは「ルートオブジェクト」から始まり、オブジェクトの関連を処理する下向きにトレースします。
  • 同時スイープ:この段階では、コレクタースレッドとアプリケーションスレッドが同時に実行されます。
  • 同時リセット:このフェーズでは、CMSコレクターのデータ構造がリセットされ、次のガベージコレクションを待ちます。

G1 GC

G1 GCは、CMSを物理的に分離するためにJDK 1.7で公式に使用されていますが、G1 GCはまだ若い世代を区別しています。 G1 GCは、最初にヒープを等しいサイズの領域に分割して、地域全体のゴミ収集を避け、次に各地域のゴミの蓄積の価値を追跡し、バックグラウンドで優先リストを維持し、許可された収集時間に基づいてG1 GCを補充するために、G1 GCの使用を覚えています。 Ans。 G1 GCパーティションの例を次の図に示します。

G1 GCの出現により、Java Garbage Collectorは、従来の連続ヒープメモリレイアウト設計から、このようにして地域の概念を動的に割り当てることにより、物理的に不連続なが論理的に連続的なメモリブロックに徐々に移動します。各領域には、RSのデータ構造がハッシュテーブルであり、内部のデータはカードテーブルです(ヒープ内の512バイトごとにカードテーブルがマッピングされます)。簡単に言えば、RSに存在するのは、地域の存続するオブジェクトのポインターです。この地域のデータが変更されると、最初にカードテーブルの1つ以上のカードに反映されます。領域を使用する過程で、領域が満たされている場合、メモリを割り当てるスレッドは新しい領域を再選択し、アイドル領域はリンクされたリストベースのデータ構造(LinkedList)に編成され、新しい領域をすばやく見つけることができます。

要約すると、G1 GCの特性は次のとおりです。

  • 並列処理:G1のリサイクル期間中、複数のGCスレッドが同時に機能し、マルチコアコンピューティング機能を効果的に利用できます。
  • 並行性:G1にはアプリケーションと交互に実行する機能があり、一部の作業はアプリケーションと同時に実行できます。そのため、一般に、リサイクルフェーズ全体でアプリケーションの完全なブロックはありません。
  • Generation GC:G1は依然として世代のリサイクル業者ですが、以前のタイプのリサイクルとは異なり、若い世代と古い世代の両方を考慮しています。若い世代で働いているか、古い世代で働いている他のリサイクルを比較してください。
  • スペースソート:リサイクルプロセス中に、G1はオブジェクトをマークしてクリーンアップするCMSとは異なり、オブジェクトを適切に移動します。いくつかのGCSの後、CMSを1回抑制する必要があります。 G1は、リサイクルするたびにオブジェクトを効果的にコピーし、断片化を減らし、内部循環速度を改善します。
  • 予測可能性:一時停止時間を短縮するために、G1はこの方法で、この方法で使用できるモデルを確立します。

G1 GCの作業手順は次のとおりです。

  • 初期タグ(GCルーツがTAMS値を直接関連付けて変更できるオブジェクトをマークします。これにはSTWが必要ですが、時間がかかります)
  • 同時タグ(ヒープオブジェクトからGCルートから生存するオブジェクトを見つけるには、長い時間がかかりますが、ユーザースレッドと同時に実行できます)を見つけるため)
  • 最終マーク(同時マーク中に変化するマークレコードの部分を修正するために、この期間中の変更は記憶されているセットログに記録され、記憶されているセットにマージされます。この段階ではSTWが必要ですが、並行して実行できます)
  • フィルターリサイクル(各地域のリサイクル値を並べ替え、リサイクルするためにユーザーの予想されるGCの一時停止時間に基づいてリサイクル計画を策定します)

[この記事は51CTOコラムニスト「張子雄」によるオリジナル記事です。転載が必要な場合は51CTOを通じて著者にご連絡ください]

この著者の他の記事を読むにはここをクリックしてください

<<:  マッキンゼーのレポート:これらの業界が人工知能に転換しなければ、ますます取り残されることになる

>>:  DeepMind: 人工知能と神経科学を組み合わせて好循環を実現

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

アマゾンとファーウェイの機械学習面接を経験すると、試験官はこれらの答えを聞きたがっていることが判明

[[245589]]ジョージ・セイフ氏はこれまで、主にデータサイエンスや機械学習関連の職種を対象に、...

2019 年のインターネット キャンパス採用の給与が発表されました。いくらもらえるか見てみましょう!

2019年秋学期のキャンパスリクルートメントは終了に近づいています。近年、特にインターネット業界で...

...

マシンビジョンは人工知能の次のフロンティアとなる

人工知能は過去1年間で大きな進歩を遂げ、人々にますます多くの利益をもたらしました。将来的には、マシン...

予測: 2019 年に爆発的に普及する 10 の人工知能テクノロジー!

1. 自然言語生成自然言語生成は、データをテキストに変換し、コンピューターがこれまでにない精度でア...

戦闘計画システムにおける人工知能技術の応用に関する研究

近年、人工知能技術は飛躍的な進歩を遂げており、各国は人工知能技術の戦略的意義を認識し、国家戦略レベル...

顔認識アプリケーションにおける人工知能の利点と欠点についての簡単な説明

1950年代にチューリングの論文「ロボットは考えることができるか?」が人工知能への扉を開いて以来、人...

...

人気の機械学習プログラミング言語、フレームワーク、ツール14選

[51CTO.com クイック翻訳] 増え続けるプログラミング言語ライブラリやツールの中から、機械学...

...

研究によると、ChatGPT は科学的仮説の偽のデータセットを生成し、学術的誠実性に脅威を与える可能性がある。

ネイチャー誌は11月24日、現地時間水曜日に、今月初めに米国医師会眼科学会誌に掲載された論文で、著者...

人工知能を理解するのに役立つ記事(画像付き)

近年、人工知能(AI)が普及するにつれ、その原理を理解できずにAIを迷信し崇拝する人が増えています。...

...

ロボットを活用する3つの革新的な方法

ロボットは、高齢の両親を助けたり、子供を教育したり、料理をしたりすることができます。ロボット産業は創...