Java-virtual-machine-generational-gcs

提供:Dev Guides
移動先:案内検索

Java仮想マシン-世代別GC

ほとんどのJVMは、ヒープを3つの世代に分割します-若い世代(YG)、古い世代(OG)、および永続的な世代(テニュア世代とも呼ばれます)。 そのような考えの背後にある理由は何ですか?

実証研究は、作成されたオブジェクトのほとんどが非常に短い寿命を持っていることを示しています-

実証研究

ソース

https://www.oracle.com

時間とともに割り当てられるオブジェクトが増えるにつれて、生き残るバイト数が少なくなることがわかります(一般的に)。 Javaオブジェクトの死亡率は高いです。

簡単な例を見てみましょう。 JavaのStringクラスは不変です。 つまり、Stringオブジェクトのコンテンツを変更する必要があるたびに、新しいオブジェクトを作成する必要があります。 以下のコードに示すように、ループ内で文字列を1000回変更するとします-

String str = “G11 GC”;

for(int i = 0 ; i < 1000; i++) {
   str = str + String.valueOf(i);
}

各ループで、新しい文字列オブジェクトを作成し、前の反復で作成された文字列は役に立たなくなります(つまり、参照によって参照されません)。 そのオブジェクトのTライフタイムは1回の繰り返しでした。GCによってすぐに収集されます。 このような短命のオブジェクトは、ヒープの若い世代の領域に保持されます。 若い世代からオブジェクトを収集するプロセスは、マイナーガベージコレクションと呼ばれ、常に「世界を止める」一時停止を引き起こします。

若い世代がいっぱいになると、GCはマイナーガベージコレクションを実行します。 デッドオブジェクトは破棄され、ライブオブジェクトは古い世代に移動します。 このプロセスの間、アプリケーションスレッドは停止します。

ここでは、このような世代設計が提供する利点を見ることができます。 若い世代はヒープのごく一部であり、すぐにいっぱいになります。 しかし、それを処理するのにかかる時間は、ヒープ全体を処理するのにかかる時間よりもはるかに短いです。 そのため、この場合の「世界停止」の一時停止は非常に短くなりますが、より頻繁に行われます。 より長い休止時間よりも短い休止時間を目標にする必要があります。 これについては、このチュートリアルの後のセクションで詳しく説明します。

若い世代は、 edenとsurvivor space の2つのスペースに分かれています。 エデンの収集中に生き残ったオブジェクトはサバイバースペースに移動し、サバイバースペースを生き残ったオブジェクトは古い世代に移動します。 若い世代は、収集中に圧縮されます。

オブジェクトが古い世代に移動すると、オブジェクトは最終的にいっぱいになり、収集して圧縮する必要があります。 アルゴリズムが異なれば、これに対するアプローチも異なります。 それらのいくつかは、アプリケーションスレッドを停止します(若い世代に比べて古い世代は非常に大きいため、長い「世界の停止」につながります)。 このプロセスはフルGCと呼ばれます。 このような2つのコレクターは、 CMSおよびG1 です。

これらのアルゴリズムを詳細に分析してみましょう。

シリアルGC

これは、クライアントクラスのマシン(シングルプロセッサマシンまたは32b JVM、Windows)のデフォルトGCです。 通常、GCは非常にマルチスレッド化されていますが、シリアルGCはそうではありません。 ヒープを処理する単一のスレッドがあり、マイナーGCまたはメジャーGCを実行するたびにアプリケーションスレッドを停止します。 フラグ -XX:+ UseSerialGC を指定することで、このGCを使用するようにJVMに命令できます。 別のアルゴリズムを使用する場合は、アルゴリズム名を指定します。 古い世代は、メジャーGCの間に完全に圧縮されることに注意してください。

スループットGC

このGCは、64b JVMおよびマルチCPUマシンのデフォルトです。 シリアルGCとは異なり、複数のスレッドを使用して、若い世代と古い世代を処理します。 このため、GCは parallel collector とも呼ばれます。 -XX:+ UseParallelOldGC または -XX:+ UseParallelGC (JDK 8以降の場合)フラグを使用して、このコレクターを使用するようにJVMに命令できます。 メジャーガベージコレクションまたはマイナーガベージコレクションを実行している間、アプリケーションスレッドは停止します。 シリアルコレクターと同様に、メジャーGC中に若い世代を完全に圧縮します。

スループットGCは、YGとOGを収集します。 エデンがいっぱいになると、コレクターはライブオブジェクトをそこからOGまたはサバイバースペースのいずれかに排出します(下図のSS0およびSS1)。 デッドオブジェクトは破棄され、占有されていたスペースが解放されます。

YGのGCの前

YGのGCの前

YGのGC後

YGのGC後

フルGC中、スループットコレクターはYG、SS0、SS1全体を空にします。 操作後、OGにはライブオブジェクトのみが含まれます。 上記の両方のコレクターは、ヒープの処理中にアプリケーションスレッドを停止することに注意してください。 これは、メジャーGCの間に長い「stopthe-world」が一時停止することを意味します。 次の2つのアルゴリズムは、より多くのハードウェアリソースを犠牲にしてそれらを排除することを目的としています-

CMSコレクター

これは「同時マークスイープ」の略です。 その機能は、バックグラウンドスレッドを使用して古い世代を定期的にスキャンし、無効なオブジェクトを取り除くことです。 ただし、マイナーGCの間、アプリケーションスレッドは停止します。 ただし、一時停止はごくわずかです。 これにより、CMSは一時停止コレクターになります。

このコレクターは、アプリケーションスレッドの実行中にヒープをスキャンするために追加のCPU時間を必要とします。 さらに、バックグラウンドスレッドはヒープを収集するだけで、圧縮は実行しません。 ヒープが断片化する可能性があります。 これが継続して行われると、特定の時点の後、CMSはすべてのアプリケーションスレッドを停止し、単一のスレッドを使用してヒープを圧縮します。 次のJVM引数を使用して、CMSコレクターを使用するようJVMに指示します-

  • 「XX:+ UseConcMarkSweepGC -XX:+ UseParNewGC」*をJVM引数として使用して、CMSコレクターを使用するように指示します。

GCの前

GCの前

GC後

GC後

収集は同時に行われていることに注意してください。

G1 GC

このアルゴリズムは、ヒープをいくつかの領域に分割することで機能します。 CMSコレクターと同様に、マイナーGCを実行中にアプリケーションスレッドを停止し、バックグラウンドスレッドを使用して、アプリケーションスレッドを維持しながら古い世代を処理します。 古い世代を領域に分割したため、オブジェクトをある領域から別の領域に移動しながらそれらを圧縮し続けます。 したがって、断片化は最小限です。 フラグ XX:+ UseG1GC を使用して、このアルゴリズムを使用するようJVMに指示できます。 CMSと同様に、ヒープの処理とアプリケーションスレッドの同時実行には、より多くのCPU時間も必要です。

このアルゴリズムは、より大きなヒープ(> 4G)を処理するように設計されており、多数の異なる領域に分割されます。 これらの地域のいくつかは若い世代を構成し、残りは古い世代を構成します。 YGは従来の方法でクリアされます。すべてのアプリケーションスレッドが停止し、古い世代またはサバイバースペースに対してまだ生きているすべてのオブジェクトです。

すべてのGCアルゴリズムがヒープをYGとOGに分割し、STWPを使用してYGをクリアすることに注意してください。 このプロセスは通常非常に高速です。