Java仮想マシン-GCの調整
前の章では、さまざまな世代別Gcsについて学びました。この章では、GCの調整方法について説明します。
ヒープサイズ
ヒープサイズは、Javaアプリケーションのパフォーマンスにおける重要な要素です。小さすぎると頻繁に充填されるため、GCで頻繁に収集する必要があります。一方、ヒープのサイズを大きくすると、収集の頻度は少なくなりますが、一時停止の長さが長くなります。
さらに、ヒープサイズを増やすと、基盤となるOSに深刻なペナルティが発生します。OSはページングを使用して、アプリケーションプログラムに実際に使用可能なメモリよりもはるかに多くのメモリを認識させます。OSは、ディスク上のスワップスペースを使用して、プログラムの非アクティブな部分をディスクにコピーすることにより、これを管理します。これらの部分が必要になると、OSはそれらをディスクからメモリにコピーして戻します。
マシンに8Gのメモリがあり、JVMが16Gの仮想メモリを認識しているとすると、JVMは、システムで実際に使用できるのは8Gしかないことを認識しません。OSから16Gを要求するだけで、そのメモリを取得すると、引き続き使用します。OSは大量のデータをスワップインおよびスワップアウトする必要があり、これはシステムのパフォーマンスを大幅に低下させます。
そして、そのような仮想メモリの完全なGC中に発生する一時停止が発生します。GCは収集と圧縮のためにヒープ全体に作用するため、仮想メモリがディスクからスワップアウトされるまで多くの待機が必要になります。並行コレクターの場合、バックグラウンドスレッドは、データがスワップスペースからメモリにコピーされるまで多くの待機が必要になります。
したがって、ここで、最適なヒープサイズをどのように決定する必要があるかという問題が発生します。最初のルールは、実際に存在するよりも多くのメモリをOSに要求しないことです。これにより、頻繁な交換の問題を完全に防ぐことができます。マシンに複数のJVMがインストールされて実行されている場合、それらすべてを合わせた合計メモリ要求は、システムに存在する実際のRAMよりも少なくなります。
2つのフラグを使用して、JVMによるメモリ要求のサイズを制御できます-
-XmsN −要求された初期メモリを制御します。
-XmxN −要求できる最大メモリを制御します。
これら両方のフラグのデフォルト値は、基盤となるOSによって異なります。たとえば、MacOSで実行されている64b JVMの場合、-XmsN = 64Mおよび-XmxN =最小1Gまたは合計物理メモリの1/4です。
JVMは2つの値の間で自動的に調整できることに注意してください。たとえば、GCが多すぎることに気付いた場合、-XmxN未満であり、目的のパフォーマンス目標が達成されている限り、メモリサイズは増加し続けます。
アプリケーションに必要なメモリ量が正確にわかっている場合は、-XmsN = -XmxNを設定できます。この場合、JVMはヒープの「最適な」値を把握する必要がないため、GCプロセスが少し効率的になります。
世代サイズ
YGに割り当てるヒープの量と、OGに割り当てるヒープの量を決定できます。これらの値は両方とも、次のようにアプリケーションのパフォーマンスに影響を与えます。
YGのサイズが非常に大きい場合、収集される頻度は低くなります。これにより、OGにプロモートされるオブジェクトの数が少なくなります。一方、OGのサイズを大きくしすぎると、収集と圧縮に時間がかかりすぎて、STWの一時停止が長くなります。したがって、ユーザーはこれら2つの値のバランスを見つける必要があります。
以下は、これらの値を設定するために使用できるフラグです-
-XX:NewRatio=N: YGとOGの比率(デフォルト値= 2)
-XX:NewSize=N: YGの初期サイズ
-XX:MaxNewSize=N: YGの最大サイズ
-XmnN: このフラグを使用して、NewSizeとMaxNewSizeを同じ値に設定します
YGの初期サイズは、与えられた式-によるNewRatioの値によって決定されます。
(total heap size) / (newRatio + 1)
newRatioの初期値は2であるため、上記の式により、YGの初期値は合計ヒープサイズの1/3になります。NewSizeフラグを使用してYGのサイズを明示的に指定することにより、この値をいつでもオーバーライドできます。このフラグにはデフォルト値がありません。明示的に設定されていない場合、YGのサイズは上記の式を使用して計算され続けます。
パーマゲンとメタスペース
permagenとmetaspaceは、JVMがクラスのメタデータを保持するヒープ領域です。このスペースは、Java 7では「permagen」と呼ばれ、Java8では「metaspace」と呼ばれます。この情報は、コンパイラーとランタイムによって使用されます。
次のフラグを使用して、permagenのサイズを制御できます。 -XX: PermSize=N そして -XX:MaxPermSize=N。Metaspaceのサイズは、以下を使用して制御できます。-XX:Metaspace- Size=N そして -XX:MaxMetaspaceSize=N。
フラグ値が設定されていない場合のpermagenとmetaspaceの管理方法にはいくつかの違いがあります。デフォルトでは、両方にデフォルトの初期サイズがあります。ただし、メタスペースは必要なだけヒープを占有できますが、permagenはデフォルトの初期値を超えて占有することはできません。たとえば、64b JVMには、最大permagenサイズとして82Mのヒープスペースがあります。
特に指定されていない限り、メタスペースは無制限の量のメモリを占有する可能性があるため、メモリ不足エラーが発生する可能性があることに注意してください。これらの領域のサイズが変更されるたびに、完全なGCが実行されます。したがって、起動時に、ロードされるクラスが多数ある場合、メタスペースはサイズ変更を継続でき、毎回完全なGCになります。したがって、初期メタスペースサイズが小さすぎる場合、大規模なアプリケーションの起動には多くの時間がかかります。起動時間が短縮されるため、初期サイズを大きくすることをお勧めします。
permagenとmetaspaceはクラスのメタデータを保持しますが、永続的ではなく、オブジェクトの場合と同様に、スペースはGCによって再利用されます。これは通常、サーバーアプリケーションの場合です。サーバーに新しいデプロイメントを行うときはいつでも、新しいクラスローダーにスペースが必要になるため、古いメタデータをクリーンアップする必要があります。このスペースはGCによって解放されます。