9 Zガベージ・コレクタ
Zガベージ・コレクタ(ZGC)はスケーラブルな低レイテンシのガベージ・コレクタです。ZGCは、アプリケーション・スレッドの実行を1ミリ秒を超えて停止せずに、負荷が高いすべての作業を同時に実行します。これは、低レイテンシが必要なアプリケーションに適しています。一時休止時間は、使用しているヒープ・サイズとは無関係です。ZGCは、数百メガバイトから16TBまでのヒープ・サイズで適切に機能します。
ZGCは、適応性が高く、必要な手動構成が最小限になるように設計されています。Javaプログラムの実行中、ZGCは、生成のサイズ変更、GCスレッド数のスケーリング、および殿堂入りしきい値の調整によって、ワークロードに動的に適応します。主なチューニング・ノブは、最大ヒープ・サイズを増やすことです。
ZGCには、新しい世代別バージョンとレガシーの非世代別バージョンの2つのバージョンがあります。非世代別ZGCは古いバージョンのZGCで、世代(「世代」を参照)を利用してランタイム特性を最適化しません。ユーザーには新しい世代別ZGCを使用するように移行することをお薦めします。
世代別ZGCは、コマンド行オプション-XX:+UseZGC -XX:+ZGenerational
を使用して有効化されます。
非世代別ZGCは、コマンドライン・オプション-XX:+UseZGC
を使用して有効化されます。
ヒープ・サイズの設定
ZGCの最も重要なチューニング・オプションは、-Xmx
コマンドライン・オプションで設定できる最大ヒープ・サイズの設定です。ZGCはコンカレント・コレクタであるため、ヒープにアプリケーションのライブセットを格納でき、GCの実行中に割当てを提供できる十分なヘッドルームがヒープ内にあるように、最大ヒープ・サイズを選択する必要があります。必要なヘッドルームの容量は、割当て率とアプリケーションのライブセットのサイズによって大きく異なります。通常、ZGCに割り当てるメモリーが多いほどよいとされています。ただし、その一方でメモリーの浪費は望ましくないため、メモリー使用量と必要なGCの実行頻度との間でバランスが取ることが重要です。
ZGCには、-XX:SoftMaxHeapSize
という名前のヒープ・サイズに関連する別のコマンドライン・オプションがあります。これを使用すると、Javaヒープが拡大できる大きさにソフト制限を設定できます。ZGCはこの制限を超えて拡大しないように努めますが、この制限を超えて最大ヒープ・サイズまで拡大することは依然として可能です。ZGCは、Javaアプリケーションの実行速度が低下し、メモリーを再利用するためにGCを待機するのを防ぐために必要な場合にのみ、ソフト制限を超える値を使用ます。たとえば、コマンドライン・オプション-Xmx5g
-XX:SoftMaxHeapSize=4g
を使用すると、ZGCでは経験則による制限として4GBが使用されますが、ヒープ・サイズを4GB未満に保つことができない場合は、一時的に5GBまで使用できます。
オペレーティング・システムへの未使用メモリーの戻し
デフォルトでは、ZGCは未使用のメモリーをコミット解除し、オペレーティング・システムに戻します。これは、メモリー・フットプリントが懸念されるアプリケーションおよび環境に役立ちますが、Javaスレッドの待機時間に悪影響を及ぼす可能性があります。コマンドライン・オプション-XX:-ZUncommit
を指定すると、この機能を無効化できます。さらに、ヒープ・サイズが最小ヒープ・サイズ(-Xms)
を下回るように、メモリーはコミット解除されません。つまり、最小ヒープ・サイズ(-Xms)
が最大ヒープ・サイズ(-Xmx)
と等しくなるように構成されている場合、この機能は暗黙的に無効になります。
未コミット遅延は、-XX:ZUncommitDelay=<seconds>
を使用して構成できます(デフォルトは300秒です)。この遅延は、メモリーが未コミットになるまでの未使用期間を指定します。
ノート:
アプリケーションの実行中にGCがメモリーをコミットおよびコミット解除できるようにすると、Javaスレッドの待機時間に悪影響を及ぼす可能性があります。ZGCで実行する主な理由が極めて低いレイテンシの場合は、-Xmx
と-Xms
に同じ値を指定して実行し、アプリケーションの起動前に-XX:+AlwaysPreTouch
を使用してメモリーにページを作成することを検討してください。
大きなページの使用
大きなページを使用するようにZGCを構成すると、通常は(スループット、レイテンシおよび起動時間の観点から)パフォーマンスが向上し、設定が少し複雑になる点を除いて、実際のデメリットはありません。通常、設定プロセスにはroot権限が必要であるため、デフォルトで有効にはなりません。
Linuxでの大きなページの有効化
Linux x86では、大きなページ(huge pagesとも呼ばれる)のサイズは2MBです。
16GBのJavaヒープが必要であるとします。つまり、16GB / 2MB = 8192のhuge pagesが必要です。
ヒープには、huge pagesのプールに対して少なくとも16GB (8192ページ)のメモリーが必要です。ヒープとJVMの他の部分では、様々な内部データ構造(コード・ヒープやビットマップのマークなど)に大きなページが使用されます。この例では、9216ページ(18GB)を予約して、2GBの非Javaヒープ割当てで大きなページを使用できるようにします。
必要なページ数を持つようにシステムのhuge pageプールを構成します(root権限が必要)。
$ echo 9216 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
カーネルがリクエストを満たす十分な空きhuge pagesを見つけられない場合、前述のコマンドの成功は保証されないことに注意してください。また、カーネルがリクエストを処理するのに時間がかかる場合があります。続行する前に、プールに割り当てられたhuge pages数をチェックし、リクエストが成功して完了したことを確認します。
$ cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
9216
Linuxでの透過的huge pagesの有効化
ノート:
Linuxでは、透過的huge pagesを有効にしたZGCを使用するには、4.7以上のカーネルが必要です。次のオプションを使用して、VMで透過的huge pagesを有効にします。
-XX:+UseLargePages -XX:+UseTransparentHugePages
これらのオプションは、マップするメモリーに対してmadvise(..., MADV_HUGEPAGE)呼出しを発行するようにJVMに指示します。これは、madvise
モードで透過的huge pagesを使用する場合に役立ちます。
透過的huge pagesを有効にするには、madvise
モードを有効にしてカーネルを構成する必要もあります。
$ echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
ZGCではヒープにshmem
huge pagesが使用されるため、次のカーネル設定も構成する必要があります。
$ echo advise > /sys/kernel/mm/transparent_hugepage/shmem_enabled
異なるGCのパフォーマンスを比較する場合は、これらのカーネル設定を確認することが重要です。一部のLinuxディストリビューションでは、/sys/kernel/mm/transparent_hugepage/enabled
をalways
に設定するように構成し、/sys/kernel/mm/transparent_hugepage/shmem_enabled
をデフォルトのnever
のままにして、プライベート・ページに対して透過的huge pagesを強制的に有効にします。この場合、ZGCを除くすべてのGCは、ヒープに対して透過的huge pagesを使用します。詳細は、『Transparent Hugepage Support』を参照してください。