エントリからJVMがZGCガベージコレクタを放棄する

Zガベージコレクターは、ZGCとも呼ばれ、jdk 11で導入され、jdk15で安定バージョンでリリースされたスケーラブルな低レイテンシーのガベージコレクターです。目的は、次の目的を達成することです。

  • <1msの最大一時停止時間(jdk <16は10ms、jdk> = 16は<1ms)。
  • 一時停止時間は、ヒープ、ライブセット、またはルートセットのサイズによって増加することはありません。
  • 8MBから16TBまでのメモリサイズのヒープを使用します。

ZGCには次の特徴があります。

  • 並行性
  • 地域ベース
  • 圧縮
  • NUMA対応
  • 色付きのポインタを使用する
  • 負荷バリアを使用する

ZGCの中心には、同時ガベージコレクターがあります。これは、Javaスレッドの実行を継続しながら、すべての手間のかかる作業が行われることを意味します。これにより、アプリケーションの応答時間に対するガベージコレクションの影響が大幅に制限されます。

ZGCの機能

ZGCコレクターは、世代を生成しないリージョンベースのメモリレイアウトです。読み取りバリア、カラーポインター、メモリマルチマッピングなどのテクノロジーを使用して、低レイテンシを最優先に、同時マークアンドソートアルゴリズムを実装します。 。ターゲットのガベージコレクター。

メモリレイアウト

ZGCには生成の概念がありません

ZGCのメモリレイアウトから始めましょう。ShenandoahやG1と同様に、ZGCもリージョンベースのヒープメモリレイアウトを使用しますが、それらとは異なり、ZGCのリージョンは動的です(動的な作成と破棄、および動的なリージョン容量)。x64ハードウェアプラットフォームでは、Region of ZGCは、大、中、小の3種類の容量を持つことができます(下の図を参照)。

  • スモールリージョン(スモールリージョン): 容量は2Mに固定されており、256K未満のオブジェクトを保存できます。
  • ZTEリージョン(ミディアムリージョン): 容量は32Mに固定されており、256K以上4M未満のオブジェクトを配置できます。
  • ラージリージョン(ラージリージョン): 容量は固定されておらず、動的に変更できますが、4MB以上のラージオブジェクトを配置するには、2MBの整数倍である必要があります。

NUMA-aware

NUMAはNMAに対応し、UMAはUniform Memory Access Architecture、NUMAはNon Uniform Memory Access Architectureです。UMAはメモリが1つしかないことを意味し、すべてのCUUがこれらのメモリにアクセスする必要があるため、競合の問題が発生します(メモリバスアクセスの競合)権利)、競合がある場合は、ロックする必要があり、ロックの効率に影響があり、CPUコアが多いほど、競合が激しくなります。NUMAの場合、各CPUには対応するメモリブロックがあり、このメモリはマザーボード上のCPUに最も近いです。各CPUはこのメモリへのアクセスを優先するため、効率は自然に向上します。

サーバーのNUMAアーキテクチャは、中規模および大規模システムで非常に人気があり、特にシステム遅延の点で高性能ソリューションです。ZGCは、NUMAアーキテクチャを自動的に認識し、NUMAアーキテクチャの特性を最大限に活用できます。 。

カラーポインタ

図に示すように、カラーポインター、つまりカラーポインターは、ZGCのコアデザインの1つです。以前のガベージコレクタのGC情報はオブジェクトポートに格納され、ZGCのGC情報はポインタに格納されます(タグ情報はオブジェクトの参照ポインタに直接記録されます)。

各オブジェクトには64ビットのポインターがあり、これらの64ビットは次のように分割されます。

  • 18ビット:将来の使用のために予約されています。
  • 1ビット:ファイナライズ可能フラグ、このビットは同時参照処理に関連し、このオブジェクトはファイナライザーを介してのみアクセスできることを示します(ファイナライザー:オブジェクト基本クラスの空のメソッド。オーバーライドされると、メソッドはGC、このメソッドは1回だけ呼び出されます)。
  • 1ビット:再マップされたフラグ。このビットの値を設定した後、オブジェクトは再配置セットを指しません(再配置セットはGCを必要とする領域セットを表します)。
  • 1ビット:Marked1ID。
  • 1ビット:Marked0の識別​​、および上記のMarked1は、GCを支援するためのマークされたオブジェクトです。
  • 42ビット:オブジェクトのアドレス(2 ^ 42 = 4Tメモリをサポートできるように):

なぜ2つのマークがあるのですか?

各GCサイクルの開始時に、使用されたフラグビットが交換され、前のGCサイクルで修正されたフラグ付き状態が無効になり、すべての参照がタグなしになります。GCサイクル1:mark0を使用すると、サイクルの終了時にすべての参照マークが01になります。GCサイクル2:サイクル1と同じようにmark1を使用すると、すべてのマークマークが10になります。

ZGCはポインター圧縮を実行できませんか?

ポインタ圧縮とは32ビットへの圧縮を指し、アドレス指定ビット数は35を超えることはできません。つまり、最大JVMメモリは32G(2 ^ 35 = 32GB)であり、ここでのアドレス指定ビット数は42ビットに達します。

カラーポインタの3つの利点は?

  1. リージョン内のすべての存続オブジェクトが(コピー後に)削除された後、元のアドレスと新しいアドレスを記録する転送テーブルがまだあるため、リージョンはすぐに解放できます。この場合、理論的には、When Regionオブジェクトは無料であり、ZGCはガベージコレクションを完了することができます。
  2. カラーポインターにはポインターの「自己修復」機能があり、書き込みバリア(インクリメンタル更新や3色マーカーの元のスナップショットなど)を減らし、問題を解決するために必要な読み取りバリアは1つだけで、数を減らします。使用されるメモリバリアの。
  3. 18個の未使用ビットがあるため、カラーポインターは非常に拡張性が高く、後続の機能の拡張に役立ちます。

マルチマップアドレッシング

異なる仮想マシンメモリから物理メモリへの変換関係は、ハードウェアレベル、オペレーティングシステムレベル、またはソフトウェアレベルで実装できます。Linuxプラットフォームでは、ZGCはマルチマッピング(マルチマッピング)を使用して、複数の異なる仮想メモリアドレスを同じ物理メモリアドレスにマッピングします。これは、多対1のマッピングです。アドレス空間は、のヒープメモリ容量よりも大きくなります。チャンス。カラーリングポインタのフラグビットをアドレスセグメントと見なします。これらの異なるアドレスセグメントが同じ福祉スペースにマッピングされている限り、複数のマッピング変換の後、カラーリングポインタを直接アドレス指定に使用できます。以下に示すように:

マルチマッピングテクノロジーは、大きなオブジェクトのコピーが簡単になるなど、確かにいくつかの追加の利点をもたらす可能性がありますが、ソースから、ZGCのマルチマッピングは、特に他の機能を実装するためではなく、色付きのポインターの派生物にすぎません。

読み取りバリア

ZGCは、読み取りバリア方式を使用してポインタ参照を修正します。ZGCはGCのコピーと並べ替えの方式を使用するため、オブジェクトの位置が変更された後、ポインタの位置が更新されていない場合、プログラムがオブジェクトを呼び出す可能性が非常に高くなります。 。オブジェクトの参照を並行して取得する場合、ZGCはオブジェクトのポインタを読み取り、再マップされたIDを決定します。IDが、オブジェクトが今回クリーニングする必要のある領域にあることである場合、オブジェクトにはメモリアドレスが変更され、元のオブジェクトの参照アドレスがポインタ内の新しい参照アドレスに置き換えられてから戻ります。

このように、読み取りバリアを使用すると、並行GCのオブジェクト読み取りの問題が解決されます。

Object o = obj.fieldA;    // Loading an object reference from heap
<load barrier needed here>
Object p = o;             // No barrier, not a load from heap
o.doSomething();          // No barrier, not a load from heap
int i = obj.fieldB;       // No barrier, not an object reference

LoadBarriersが存在すると、ZGCで構成されたアプリケーションのスループットが低下します。公式のテストデータは、さらに4%のオーバーヘッドです。

ZGC作業プロセス

ZGCの運用プロセスは、次の4つの段階に分けることができます。

ZGC処理process.png

コンカレントマーク:G1やシェナンドアと同様に、コンカレントマークは到達可能性分析のためにオブジェクトグラフをトラバースする段階であり、G1やシェナンドアと同様に前後に最初のマークと最後のマークを通過します(ただし、ZGCの名前は呼び出されません)これら)は短い一時停止であり、これらの一時停止の目的は似ています。G1およびShenandoahとは異なり、ZGCのマーキングはオブジェクトではなくポインターで実行され、染色されたポインターのMarked0およびMarked1フラグはマーキングフェーズで更新されます。

再配置の同時準備(再配置の同時準備):この段階で、特定のクエリ条件に従って、この収集プロセスでクリーンアップするリージョンを計算し、これらのリージョンを再配置セット(再配置セット)に形成する必要があります。再配布セットは、G1コレクターのコレクションセットとはまだ異なります。ZGCのリージョンの分割の目的は、G1のように収益を優先して増分コレクションを実行することではありません。それどころか、ZGCは各コレクションのすべてのリージョンをスキャンし、より広い範囲をスキャンするコストをG1に設定されたメモリのメンテナンスコストと交換します。したがって、ZGCの再割り当てセットは、その中の生き残ったオブジェクトが他のリージョンに再コピーされ、その中のリージョンが解放されることを決定するだけですが、リカバリ動作がこの中のリージョンに対してのみ実行されるとは言えません。マーキングプロセスはフルヒープ用であるため、設定されます。さらに、JDK 12のZGCでサポートされている弱参照のクラスのアンロードと処理も、このフェーズで完了します。

同時再配置:再割り当ては、ZGCの実行プロセスのコアステージです。このプロセスでは、再割り当てセット内の残りのオブジェクトが新しいリージョンにコピーされ、再割り当てセット内のリージョンごとに転送テーブルが維持されます(転送テーブル)。 、古いオブジェクトから新しいオブジェクトへの転送関係を記録します。色付きのポインタのサポートのおかげで、ZGCコレクターは、オブジェクトが再割り当てセットにあるかどうかを参照からのみ明確に知ることができます。この時点でユーザースレッドが再割り当てセット内のオブジェクトに同時にアクセスすると、アクセスはインターセプトされます。メモリバリアを事前設定し、リージョンの転送テーブルレコードに従って、新しくコピーされたオブジェクトへのアクセスをすぐに転送すると同時に、参照の値を修正および更新して、新しいオブジェクトを直接指すようにします。ZGC呼び出しこの動作。ポインタの「自己修復」(自己修復)機能の場合。

これの利点は、古いオブジェクトへの最初のアクセスのみが転送に分類されることです。つまり、1回だけ低速になります。ShenandoahのBrooks転送ポインターと比較すると、オブジェクトへのアクセスごとに支払う必要のある固定オーバーヘッドです。つまり、毎回遅いので、ユーザープログラムでのZGCの実行時の負荷はShenandoahよりも低くなります。もう1つの直接的な利点は、染色されたポインタが存在するため、再割り当てセット内のリージョンの残りのオブジェクトがコピーされると、新しいオブジェクトの割り当てのためにリージョンをすぐに解放できることです(ただし、転送テーブルは保持する必要があります。 freed)、ヒープ内にこのオブジェクトへの更新されていないポインタがまだたくさんある場合でも、問題ではありません。これらの古いポインタは、使用されると自動的に回復します。

コンカレントリマップ:リマッピングが行うことは、ヒープ全体に設定された再割り当て内の古いオブジェクトへのすべての参照を修正することです。これは、ターゲットの観点からはShenandoahコンカレント参照更新フェーズと同じですが、ZGCのコンカレントリマッピングは「先に述べたように、それが古い参照であっても、それが初めて使用されるとき、せいぜいもう1つの転送および修正操作で、自己回復する可能性があるため、完了する必要があります。これらの古い参照をクリーンアップするための再マッピングの主な目的は、速度が低下しないこと(および、クリーンアップの完了後に転送テーブルを解放することの副次的な利点)であるため、それほど「緊急」ではありません。したがって、ZGCは、同時再マッピングフェーズで実行される作業を、次のガベージコレクションサイクルの同時マーキングフェーズに巧みにマージして完了します。とにかく、すべてのオブジェクトをトラバースする必要があるため、マージによりオブジェクトのトラバースが節約されます。 。すべてのポインタが修正されると、古いオブジェクトと新しいオブジェクトの関係を最初に記録した転送テーブルを解放できます。

ZGCコアパラメータ

ZGCトリガータイミング

ZGCのいくつかのトリガーGCシナリオ:

  • タイミングトリガー: デフォルトでは使用されず、ZCollectionIntervalパラメーターを使用して構成できます。GCログのキーワード「タイマー」。
  • ウォームアップトリガー: 最大3回、ヒープメモリスペースが主にGCの時間を通じて10%、20%、および30%に達したときにトリガーし、他のGCトリガーの準備をします。GCログキーワード「ウォーミングアップ」。
  • 割り当て率: 正規分布統計に基づいて、メモリの99%の可能な最大割り当て率を計算し、この率でメモリが使い果たされる時点を計算し、使い果たされる前にGCをトリガーします(枯渇時間、1つのGCの最大期間-1つのGC検出サイクル時間)。GCログキーワード「割り当て率」。
  • アクティブトリガー:( デフォルトで有効、ZProactictiveパラメーターで構成可能)ヒープメモリは最後のGCから10%増加します。5分を超える場合は、最後のGCの間隔制限時間(GCの最大期間)を比較します。 、を超えた場合にトリガーします。GCログキーワード「プロアクティブ」。
  • メタデータ割り当てトリガー: メタデータ領域が不十分なため、GCログキーは「メタデータGCしきい値」です。
  • 直接トリガー: コードは、System.gc()の呼び出しがトリガーされ、GCログキーワードが「System.gc()」であることを示しています。
  • トリガーされたメモリ割り当て要求のブロック: ガベージオブジェクトは手を振る時間がなく、ヒープスペース全体を占有し、一部のスレッドをブロックします。GCログキーワードは「割り当てストール」です。

ZGCログ分析

以下の簡単なプログラムのZGCLOGの分析を行います。以下は、特定のコードと分析です。

サンプルコード

簡単なコードを次に示します。

/**
 * VM Args:-XX:+UseZGC -Xmx8m -Xlog:gc*
 */
public class HeapOOM {

    public static void main(String[] args) {
        List<byte[]> list = new ArrayList<>();
        while (true) {
            list.add(new byte[2048]);
        }
    }
}

GCログ分析

GCログは次のとおりです(動作環境はJDK 17です)。たとえば、GCログの各行には、GCプロセスに関する情報がマークされています。重要な情報は次のとおりです。

  • 開始:  GCを開始し、GCトリガーの理由を示します。上の図のトリガーは、適応アルゴリズムです。
  • フェーズ-一時停止マーク開始: 初期マーク、STWになります。
  • フェーズ一時停止マーク終了: もう一度マークし、STWします。
  • フェーズ-一時停止再配置開始: 最初の転送、STWになります。

ヒープ情報:GC中のMarkandRelocateの前後のヒープサイズの変更を記録します。HighとLowは、最大値と最小値を記録します。通常、Used in Highの値に注意します。100%に達すると、GCプロセス中にメモリ割り当てが不十分になる可能性があります。GCのトリガータイミングを調整する必要があります。以前または以前。GCが高速。

GC情報統計:ガベージコレクション情報を定期的に印刷し、起動から現在までのすべての統計を10秒、10分、および10時間以内に監視できます。これらの統計を使用して、トラブルシューティングを行い、いくつかの異常なポイントを見つけることができます。

ZGCの概要

本稿では、主にZGCの特徴と作業プロセスを概念的に説明します。

現在、ほとんどのインターネット企業は依然としてjdk8とjdk11を使用しています。主流の用途はParNew+CMSの組み合わせまたはG1です。

最前線のJava開発者にとって、激しい社会的競争で優位に立つためには、新しいテクノロジーを学ぶことに熱意と注意を払う必要があります。

おすすめ

転載: blog.csdn.net/Trouvailless/article/details/124273204