7種類のJAVAガベージコレクタ
この文書では、Javaのガベージコレクタとは何か、ガベージコレクタの主な種類と各ガベージコレクタの動作について説明します。 また、この記事では、ヒープの割り当てがどのように行われ、メジャー/マイナーガベージコレクタが開始されるかは説明していないことに注意してください。 それは次の記事で説明します。
Java はオブジェクト指向のプログラミング言語であり、自動ガベージコレクションが含まれています。 Javaは自動的にメモリの確保と解放を行うため、プログラムにその作業を負担させることはありません。 現在(Java-12)、Javaには7種類のガベージコレクタがあります。
- シリアルガーベジコレクタ
- パラレルガーベジコレクタ
- CMSガーベジコレクタ
- G1ガーベジコレクタ
- イプシロンガーベジコレクタ
- Epsilon Garbage CollectionZ garbage collector
- Shenandoah Garbage Collector
Java 11で5番目と6番目のガベージコレクタが、java 12で7番目のものが導入されている。 生産中のほとんどのアプリケーションでは、ガベージコレクタの最初の4つのタイプを使用しています。
GC について心配する必要がありますか。
はい、確かにそうです。 私たちは GC とその動作について心配しなければなりません。 なぜなら、それは重要なパフォーマンスの違いを提供することができるからです。 各GCにはそれぞれ利点と欠点があります。 開発者として、私たちはすべてのガベージコレクタの動作について明確なアイデアを持っている必要があり、私たちのビジネスシナリオに基づいてガベージコレクタを選択する必要があります。 5177>
Serial Garbage Collector
これは最も単純な GC の実装です。 これは基本的にシングルスレッド環境のために設計されています。 このGC実装は、それが実行されたときに、すべてのアプリケーションスレッドをフリーズします。 これは、ガベージコレクションのためのシングルスレッドを使用しています。
Serial Garbage Collector を有効にするには、次の引数を使用できます。
java -XX:+UseSerialGC -jar Application.java
Parallel Garbage Collector
The parallel garbage collector is also called as a throughput collector.これは、スルーパッドコレクタとも呼ばれます。 シリアル ガーベッジコレクタとは異なり、これはガーベッジコレクションに複数のスレッドを使用します。 シリアル ガーベッジコレクタと同様に、ガーベッジコレクションを実行中にすべてのアプリケーション スレッドをフリーズします。 ガベージコレクタは、アプリケーションの一時停止に耐えられるアプリケーションに最適です。
並列ガベージコレクタを有効にするには、次の引数を使用できます:
java -XX:+UseParallelGC -jar Application.java
この GC を使用する場合、最大ガベージコレクション スレッド数と一時停止時間、スループットとフットプリント(ヒープ サイズ)を指定できます
ガベージコレクタ スレッドの数は、コマンドライン オプション
-XX で制御可能です。ParallelGCThreads=<N>
最大の休止時間目標 (2 つの GC 間のギャップ) は、コマンドライン・オプション
-XX で指定されます。MaxGCPauseMillis=<N>
最大スループット目標 (ガベージコレクションの外で費やされた時間に対して費やされた時間に関して測定) は、コマンドライン オプション
-XX.X で指定された場合、ガベージコレクションの実行中に費やされた時間が、最大スループットの目標になります。GCTimeRatio=<N>
最大ヒープフットプリント (実行中にプログラムが必要とするヒープメモリの量) は、-Xmx<N> オプションを使用して指定されます。
CMS ガーベッジコレクタ
Concurrent Mark Sweep (CMS) ガーベッジコレクタは、ガーベッジコレクタのスレッドを複数使用し、ガーベッジコレクションを行います。 これは、ヒープ・メモリをスキャンして、立ち退きのためにインスタンスをマークし、その後、マークされたインスタンスを掃引します。 これは、ガベージ コレクションの休止時間が短いことを好み、アプリケーションの実行中にガベージコレクタとプロセッサ リソースを共有する余裕があるアプリケーション向けに設計されています。
CMS ガベージコレクタは、次の 2 つのシナリオでのみすべてのアプリケーション スレッドを保持します
- 古い世代空間の参照オブジェクトをマークする間。
- ガベージコレクションを行うのと並行してヒープメモリを変更する場合
並列ガベージコレクタと比較して、CMSコレクタはより良いアプリケーションスループットを確保するためにより多くのCPUを使っています。 より良いパフォーマンスのためにより多くの CPU を割り当てることができる場合、CMS ガーベッジコレクターは並列コレクターよりも好ましい選択です。
CMS ガーベッジコレクターを有効にするには、次の引数を使用できます。java
G1 Garbage Collector
G1 (Garbage First) Garbage Collector は、大きなメモリ空間を持つマルチプロセッサ マシンで実行するアプリケーション向けに設計されています。 JDK7 Update 4 以降のリリースで利用可能です。
G1 はヒープメモリを領域に分割し、その領域内で並行して収集を実行します。 また、G1 は、メモリを再利用した直後に、空きヒープ領域をコンパクトにすることも行います。 しかし、CMSガベージコレクタは、Stop the World (STW)の状況でメモリをコンパクトにします。
G1コレクタには2つのフェーズがあります。
- Marking
- Sweeping
他のコレクタとは異なり、G1コレクタはヒープを同じサイズのヒープ領域、それぞれ仮想メモリの連続した領域に分割しています。 ガベージコレクションを実行するとき、G1はヒープ全体のオブジェクトの活性を決定するために、同時にグローバルなマーク段階を示す。
マーク段階が完了した後、G1はどの領域がほとんど空であるかを知っている。 G1 はこれらの領域で最初に収集し、通常、かなりの量の空き領域が得られます。 G1 ガーベッジコレクターを有効にするには、次の引数を使用できます。
java -XX:+UseG1GC -jar Application.java
Epsilon Garbage Collector
Epsilon は非運用またはパッシブのガーベッジコレクターです。 アプリケーションのためにメモリを割り当てますが、未使用のオブジェクトを収集することはありません。 アプリケーションがJavaヒープを使い果たしたとき、JVMはシャットダウンします。 これは、イプシロンガベージコレクタが、アプリケーションがメモリ不足になり、クラッシュすることを許可していることを意味します。
このガベージコレクタの目的は、アプリケーションパフォーマンスの測定と管理です。 アクティブなガベージコレクタは、アプリケーションと一緒に JVM 内部で実行される複雑なプログラムです。 Epsilonは、GCがパフォーマンスに与える影響を除去します。 GCサイクルや読み取り、書き込みのバリアはありません。 エプシロンGCを使用する場合、コードは分離して実行されます。 Epsilonは、ガベージコレクションがアプリのパフォーマンスにどのように影響するか、また、メモリが枯渇したときに表示されるので、メモリの閾値が何であるかを視覚化するのに役立ちます。 例えば、アプリケーションに1ギガバイトのメモリしか必要ないと考えている場合、-Xmx1gで実行し、その挙動を確認することができます。 もし、そのメモリ割り当てで十分でない場合は、ヒープダンプをとって再実行します。 ヒープダンプを取得するためには、このオプションを有効にしなければならないことに注意してください。 5177>
XX:HeapDumpOnOutOfMemoryError
アプリケーションからパフォーマンスのすべてのビットを絞り出す必要がある場合、Epsilon は GC のための最良の選択肢かもしれません。 しかし、私たちのコードがどのようにメモリを使用するかを完全に理解する必要があります。 Epsilon ガーベッジ コレクタを有効にするには、次の引数を使用できます。
java -XX:+UseEpsilonGC -jar Application.java
Z ガーベッジコレクタ
ZGC は、アプリケーション スレッドの実行を 10ms 以上停止せずに、すべての高価な作業を同時に実行するので、低レイテンシーが必要なアプリケーションや非常に大きなヒープを使用するアプリケーションに適しています。 Oracleのドキュメントによると、数テラバイトのヒープを扱うことができる。 Oracle社はJava 11でZGCを導入した。 Zガベージコレクタは、そのスレッドでサイクルを実行する。 平均1msの間、アプリケーションを一時停止します。 G1 と Parallel コレクターは平均約 200ms です。
Java 12 で、Oracle はパフォーマンスの修正とクラスのアンロードを追加しましたが、Z はまだ実験的なステータスでした。 これは 64 ビット Linux でのみ利用可能です。 しかし、ZGCはポインタのカラーリングと呼ばれる技術で64ビットポインタを利用します。 カラーリングされたポインタは、ヒープ上のオブジェクトに関する余分な情報を保存します。 これが、64ビットJVMに限定される理由の一つです。 この記事では、このシナリオを深く説明しています (https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/)。
ZGC は 3 つのフェーズでマーキングを行います。 短いstop-the-worldフェーズ – GCルート、ヒープの残りの部分を指すローカル変数を調べます。 これらのルートの総数は通常最小で、負荷の大きさに比例しないため、ZGC の一時停止は非常に短く、ヒープが大きくなっても増加しません。
2. 同時実行フェーズ – オブジェクトグラフを歩き、色付きポインタを調べ、アクセス可能なオブジェクトをマークします。 ロードバリアは GC フェーズと任意のアプリケーションの活動の間の競合を防ぎます。
3. リロケーション・フェーズ – より速く割り当てを行うために、ヒープの大きなセクションを解放するためにライブオブジェクトを移動します。 再配置フェーズが始まると、ZGC はヒープをページに分割し、一度に 1 ページずつ作業します。 ZGC が任意のルートを移動し終えると、残りの再配置は同時進行フェーズで行われます。
ZGC はスレッドの数を自分で設定しようとし、通常は正しく設定されます。 しかし、ZGC にスレッドが多すぎると、アプリケーションを飢えさせることになります。 十分でない場合は、GC が収集できるよりも速くゴミを生成することになります。 ZGC のフェーズでは、アプリケーション メモリが大きくなってもパフォーマンスに影響を与えることなく、大きなヒープを管理する方法を説明します。
Z Garbage Collector を有効にするには、次の引数を使用できます:
java -XX:+UseZGC -jar Application.java
Shenandoah
Shenandoah は、実行中の Java プログラムと同時に多くのガベージ コレクション作業を行うことにより、GC の一時停止時間を短縮する超低一時停止ガベージ コレクタです。 CMSとG1は両方とも生きているオブジェクトの同時マークを実行します。
Shenandoah は、どのオブジェクトがもはや使用されておらず、どれが生きていて圧縮の準備ができているかを管理するために、メモリ領域を使用します。 また、Shenandoah は、すべてのヒープオブジェクトに転送ポインタを追加し、それを使用してオブジェクトへのアクセスを制御します。 Shenandoahのデザインは、同時CPUサイクルとスペースを一時停止時間の改善と引き換えにするものです。 転送ポインタは、オブジェクトの移動を容易にしますが、積極的な移動は、Shenandoahが他のGCよりも多くのメモリを使用し、より多くの並列作業を必要とすることを意味します。 しかし、それは非常に短いStop-the-World休止で余分な仕事をします。
Shenandoah は多くの小さなフェーズでヒープを処理し、そのほとんどはアプリケーションと同時に行われます。 この設計により、GCは大きなヒープを効率的に管理することができる。
- サイクルの最初のstop-the-worldポーズ。 これは、同時マーキングのためにヒープを準備し、ルートセットをスキャンします。 ZGCのように、この休止の長さはヒープではなくルートセットのサイズに対応する。
- 次に、同時実行フェーズがヒープを歩き、到達可能なオブジェクトと到達不可能なオブジェクトを識別する。 このフェーズは、サイクルの2回目のStop-the-Worldポーズをトリガします。 保留中の更新の数とルート セットのサイズが、一時停止の長さを決定します。
- その後、別の同時進行フェーズでは、最後のマーク フェーズで識別された領域からオブジェクトをコピーします。 このプロセスは、アプリケーションスレッドと並行して積極的にヒープをコンパクトにするので、Shenandoahを他のGCと区別します。
- 次のフェーズは、サイクルの3番目の(そして最も短い)休止をトリガーします。 これは、すべてのGCスレッドが退避を終了したことを保証する。
- それが終了すると、同時進行のフェーズがヒープを歩き、サイクルの早い段階で移動したオブジェクトへの参照を更新する。
- サイクルの最後のストップ・ザ・ワールド休止は、ルートセットを更新して参照の更新を終了させる。
- 最後に、最後のフェーズでは、退避した領域を取り戻し、その領域には現在参照がない。
我々は、3つのヒューリスティックのうちの1つとShenandoahを構成することができる。 これらは、GCがそのサイクルを開始するときと、避難のための領域を選択する方法を制御します。 適応型。 GCのサイクルを観察し、アプリケーションがヒープを使い果たす前に完了するように次のサイクルを開始します。 このヒューリスティックは、デフォルトのモードです。 ヒープ占有率と割り当て圧力に基づいてGCサイクルを開始します。
3: GCサイクルを連続的に実行します。 Shenandoahは、前のサイクルが終了するとすぐに、または最後のサイクルから割り当てられたヒープの量に基づいて、新しいサイクルを開始します。 このヒューリスティックは、スループット オーバーヘッドを発生させますが、最高のスペース再利用を提供します。
Shenandoah は、提供しているアプリケーションがそれを割り当てるよりも速くヒープを収集する必要があります。 割り当て圧力が高すぎて、新しい割り当てのための十分なスペースがない場合、障害が発生します。 Shenandoah は、この状況のために設定可能なメカニズムを備えています。 Shenandoahが割り当ての速度に遅れ始めると、追いつくために割り当てスレッドをストールさせます。 このストールは、通常、軽度のアロケーションスパイクには十分です。 Shenandoahは、10ms以下の遅延を導入します。 ペーシングが失敗すると、Shenandoahは次のステップに移ります:縮退GC.
Shenandoah は、大きなヒープで ZGC と同じ利点を提供しますが、より多くのチューニングオプションを提供します。 アプリケーションの性質によっては、異なるヒューリスティックがうまくフィットするかもしれません。 その一時停止時間は ZGC ほど短くないかもしれませんが、より予測可能です。
Shenandoah ガーベッジコレクターを有効にするには、次の引数を使用できます。java
Conclusion
この記事の全体的な目的は、すべてのガベージコレクタを要約することである。 したがって、いくつかの内容は、与えられたリファレンスから抽出されたものである。 私たちのアプリケーションのユースケースに最適なガベージコレクタを選択するために、ガベージコレクタについて明確な考えを持つ必要があります。
Reference
- https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
- https://www.baeldung.com/jvm-garbage-collectors
- https://dzone.com/articles/java-garbage-collection-3
- https://www.opsian.com/blog/javas-new-zgc-is-very-exciting/
- https://openjdk.java.net/projects/shenandoah/
- https://docs.oracle.com/en/java/javase/12/gctuning/z-garbage-collector1.html#GUID-A5A42691-095E-47BA-B6DC-FB4E5FAA43D0
- http://clojure-goes-fast.com/blog/shenandoah-in-production/
にあるガベージコレクタの概要