Javaのガベージコレクションは、高度なトピックの一つです。JavaのGCの知識は、アプリケーションの実行時パフォーマンスを微調整するのに役立ちます。
Javaのガベージコレクション
- Javaでは、プログラマーは使用されなくなったオブジェクトを破棄する必要はありません。ガベージコレクタがそれを処理します。
- ガベージコレクタはバックグラウンドで実行されるデーモンスレッドです。基本的には、到達不能なオブジェクトを破棄してヒープメモリを解放します。
- 到達不能なオブジェクトは、プログラムのどの部分からも参照されなくなったオブジェクトです。
- Javaプログラムのガベージコレクタは、JVMオプションを通じて選択することができます。このチュートリアルの後のセクションで詳しく説明します。
自動ガベージコレクションの動作原理
{
“error”: “Upstream error…”
}
Javaガベージコレクター
JVMは実際には4つの異なるガベージコレクターを提供しており、すべてが世代別です。それぞれには利点と欠点があります。どのガベージコレクターを使用するかの選択は私たちにあり、スループットとアプリケーションの一時停止には劇的な違いがある場合があります。すべてのガベージコレクターは、管理されたヒープを異なるセグメントに分割し、ヒープ内のほとんどのオブジェクトは短命であるという古い仮定を使用して、迅速にリサイクルする必要があるという考えに基づいています。したがって、4つのタイプのガベージコレクターは以下の通りです:
シリアルGC
これは最も単純なガベージコレクターであり、シングルスレッドのシステムと小さなヒープサイズ向けに設計されています。作業中にすべてのアプリケーションを凍結します。JVMオプション-XX:+UseSerialGC
を使用して有効にできます。
パラレル/スループットGC
これはJDK 8のJVMのデフォルトコレクタです。その名前が示すように、複数のスレッドを使用してヒープスペースをスキャンし、コンパクションを実行します。このコレクタの欠点は、マイナーまたはフルGCを実行する間にアプリケーションスレッドを一時停止させることです。このコレクタは、そのような一時停止を処理できるアプリケーションに最適であり、コレクタによって引き起こされるCPUオーバーヘッドを最適化しようとします。
CMSコレクタ
CMSコレクタ(「concurrent-mark-sweep」)アルゴリズムは、未使用のオブジェクトを再利用できるようにヒープ(「mark」)をスキャンするために複数のスレッド(「concurrent」)を使用します。このコレクタは、次の2つの場合にStop-The-World(STW)モードに入ります:-ルートの初期マーキング中に、つまり、スレッドエントリーポイントまたは静的変数から到達可能な古い世代のオブジェクトの初期マーキング中-アプリケーションがアルゴリズムが並行して実行されている間にヒープの状態を変更し、正しいオブジェクトがマークされるように最終的なタッチアップを行うために強制する場合、このコレクタは昇進の失敗に直面する場合があります。若い世代から古い世代に移動するオブジェクトがあり、コレクタに十分な時間がなかった場合に、昇進の失敗が発生します。これを防ぐために、古い世代により多くのヒープサイズを提供するか、コレクタにより多くのバックグラウンドスレッドを提供することができます。
G1コレクタ
最後になりますが、Garbage-Firstコレクタは4GB以上のヒープサイズに対して設計されています。ヒープサイズに基づいて1MBから32MBまでの領域に分割されます。ヒープ全体のオブジェクトの生存状態を判定するための並行グローバルマーキングフェーズがあります。マーキングフェーズが完了した後、G1は主に空の領域を持つリージョンを把握します。これらのリージョンには到達不可能なオブジェクトが多く含まれています。そのため、G1はまずこれらのガベージを収集します。そのため、「Garbage-First」という名前が付けられています。G1はまた、ユーザー定義の一時停止時間目標を満たすために一時停止予測モデルを使用します。指定された一時停止時間目標に基づいて収集するリージョンの数を選択します。G1ガベージコレクションサイクルには、以下の図に示されているフェーズが含まれます:
-
Young-onlyフェーズ:このフェーズには若い世代のオブジェクトのみが含まれ、それらは古い世代に昇格します。Young-onlyフェーズと空間回収フェーズの遷移は、古い世代がある閾値(イニシエートヒープ占有率の閾値)まで占有された時に開始されます。この時点で、G1は通常のYoung-onlyコレクションではなく、初期マークのYoung-onlyコレクションをスケジュールします。
-
初期マーキング:このタイプのコレクションは、通常の若年者専用コレクションに加えてマーキングプロセスを開始します。並行マーキングにより、老年者領域に現在生存しているすべてのオブジェクトが、次の空間回収フェーズのために保持されることが決定されます。マーキングが完全に終了していない間は、通常の若年者専用コレクションが発生する場合があります。マーキングは、RemarkとCleanupという2つの特別な停止ワールドの一時停止で終了します。
-
Remark:この一時停止では、マーキング自体を最終化し、グローバルな参照処理とクラスのアンローディングを行います。RemarkとCleanupの間で、G1は非同期に生存情報の要約を計算し、これはCleanupの一時停止で最終化され、内部のデータ構造を更新するために使用されます。
-
Cleanup:このポーズでは、完全に空の領域も取り扱い、実際にスペース回収フェーズが続くかどうかを判断します。スペース回収フェーズが続く場合、若年世代のみのフェーズは単一の若年世代のコレクションで完了します。
-
スペース回収フェーズ:このフェーズでは、複数の混合コレクションが行われます。若年世代領域だけでなく、古年世代領域の生存オブジェクトも移動します。スペース回収フェーズは、G1がさらに古年世代領域を移動しても十分な空きスペースが得られないと判断したときに終了します。
G1は、–XX:+UseG1GC
フラグを使用して有効にできます。この戦略により、バックグラウンドスレッドが到達不可能なオブジェクトのスキャンを終える前に、ヒープが枯渇する可能性が低くなります。また、G1はヒープをオンザフライでコンパクト化することができますが、CMSコレクタはSTWモードでしか行えません。Java 8では、G1コレクタには文字列の重複排除という美しい最適化が提供されています。私たちの文字列を表す文字配列は、ヒープスペースの大部分を占めていることがわかっています。新しい最適化では、G1コレクタがヒープ全体で複数回複製されている文字列を特定し、それらを同じ内部char[]配列を指すように変更することで、同じ文字列の複数のコピーが不必要にヒープに存在することを避けることができます。この最適化を有効にするには、-XX:+UseStringDeduplication
JVM引数を使用できます。G1はJDK 9でデフォルトのガベージコレクタです。
Java 8のPermGenとMetaspace
先述の通り、Java 8以降、Permanent Generationスペースは削除されました。そのため、JDK 8 HotSpot JVMでは、クラスのメタデータの表現にネイティブメモリが使用されるようになりました。これをメタスペースと呼びます。クラスのメタデータのほとんどはネイティブメモリから割り当てられます。また、クラスメタデータに使用するメモリ量を制限するために、新しいフラグMaxMetaspaceSizeが導入されました。この値を指定しない場合、実行中のアプリケーションの需要に応じてメタスペースはランタイムでサイズ変更されます。メタスペースのガベージコレクションは、クラスのメタデータの使用量がMaxMetaspaceSizeの制限に達したときにトリガーされます。メタスペースのガベージコレクションが過剰に行われる場合、クラスやクラスローダーのメモリリーク、またはアプリケーションの適切なサイズ設定の不足が考えられます。以上がJavaにおけるガベージコレクションについての説明です。Javaで使用可能なさまざまなガベージコレクターについての理解が深まったことを願っています。参考文献:Oracleのドキュメント、G1 GC。
Source:
https://www.digitalocean.com/community/tutorials/garbage-collection-in-java