ホームページ  >  記事  >  Java  >  Java ガベージ コレクションのメカニズムを理解する

Java ガベージ コレクションのメカニズムを理解する

WBOY
WBOY転載
2023-04-24 14:10:07956ブラウズ

メモリ セットとカード テーブルについて話す前に、まず世代間参照の問題について紹介します。

Java ガベージ コレクションのメカニズムを理解する

新世代領域に限定したコレクション(マイナーGC)を行いたいが、新世代のインスタンスオブジェクト1が旧世代で参照されている場合を見つけるには、この領域 (新しい世代) で生き残っているすべてのオブジェクトを削除するには、固定された GC ルートに加えて、古い世代全体のすべてのオブジェクトをさらに走査して、到達可能性分析結果の正確性を確認する必要があります。その逆も。古い世代全体のすべてのオブジェクトを走査するという解決策は理論的には実現可能ですが、メモリのリサイクルに大きなパフォーマンスの負荷がかかることは間違いありません。

実際、世代間の参照の問題は、新世代と旧世代の間だけでなく、G1、ZGC、Shenandoah など、部分領域コレクション (部分 GC) 動作を伴うすべてのガベージ コレクターにも発生します。すべてのデバイスが同じ問題に直面します。

では、世代間参照を解決するにはどうすればよいでしょうか?

まず第一に、世代を越えた引用は、同世代の引用と比較して非常に少数にすぎません。その理由は、世代を超えて参照されるオブジェクトは同時に存続するか消滅する傾向があるためです (たとえば、新しい世代のオブジェクトに世代間の参照がある場合、古い世代のオブジェクトは消滅しにくいため、この参照により新しい世代のオブジェクトが存続することが可能になります)世代オブジェクトは収集時に収集されます。存続し、古くなると古い世代に昇格します。その際、世代間の参照も削除されます)。

上記の内容に基づいて、少数の世代間参照を見つけるために古い世代全体をスキャンする必要もなくなりました。また、各オブジェクトが存在するかどうか、およびどのオブジェクトがどの世代間の参照であるかを記録するためにスペースを無駄にする必要もなくなりました。世代参照が存在します。古い世代全体をスキャンして、少数の世代間参照を確認するだけで済みます。グローバル データ構造を作成します (この構造は「記憶セット」と呼ばれます)。この構造は、古い世代をいくつかの小さなブロックに分割します。そして、古い世代のどのメモリ部分が世代間参照を持つかを特定します。その後、マイナー GC が発生すると、世代間参照を含むメモリの小さなブロック内のオブジェクトのみがスキャンのために GCRoot に追加されます。この方法では、オブジェクトの参照関係が変更された場合 (オブジェクト自体や特定の属性の割り当てなど)、記録されたデータの正確さを維持する必要があり、実行時のオーバーヘッドが若干増加しますが、それでも古い世代全体をスキャンするよりもコスト効率が高くなります。収集中のものです。

このグローバル データ構造メモリ セットを紹介しましょう。

メモリ セット

メモリ セットは、非収集領域から収集領域へのポインタのセットを記録するために使用される抽象データ構造です。効率とコストを考慮しない場合、最も単純な実装では、次のコードに示すように、非コレクション領域に世代間参照を含むすべてのオブジェクト配列を使用してこのデータ構造を実装できます。レコード 世代間の参照オブジェクトを含む実装ソリューションは、スペース使用量と保守コストの点で非常に高価です。ガベージ コレクションのシナリオでは、コレクターはメモリ セットを使用して、特定の非コレクション領域にコレクション領域を指すポインターがあるかどうかを判断するだけでよく、これらの世代間ポインターの詳細をすべて知る必要はありません。設計者はメモリ セットを実装するときに、メモリ セットのストレージとメンテナンスのコストを節約するために、より粗いレコード粒度を選択できます。以下に、選択できるレコードの精度をいくつか示します (もちろん、この範囲外を選択することもできます):

    ワード長の精度: 各レコードは 1 つのマシン語長まで正確です (つまり、プロセッサ (一般的な 32 ビットまたは 64 ビットなどのアドレス指定ビットの数、この精度によってマシンが物理メモリ アドレスにアクセスするために使用するポインタの長さが決まります)、このワードには世代間ポインタが含まれます。
  • オブジェクトの精度: 各レコードはオブジェクトに対して正確であり、オブジェクトには世代間のポインターを含むフィールドがあります。
  • カードの精度: 各レコードはメモリ領域に対して正確であり、この領域には世代間ポインタを含むオブジェクトがあります。
  • 上記の 3 番目のタイプの「カード精度」は、「カード テーブル」と呼ばれるメソッドを使用してメモリ セットを実装することを指します。これは、現在最も一般的に使用されているメモリ セットの実装です。

カードリストとメモリーセットの関係は何ですか?

以前にメモリ セットを紹介したとき、メモリ セットは実際には「抽象」データ構造であると述べました。抽象化とは、メモリ セットの動作上の意図を定義するだけであり、メモリ セットの特定の実装を定義するものではないことを意味します。その振る舞い。カード テーブルはメモリ セットの特定の実装であり、メモリ セットの記録精度、ヒープ メモリとのマッピング関係などを定義します。メモリセットとカードテーブルの関係は、JavaにおけるMapとHashMapの関係(つまり、インターフェースと実装クラスの関係)から類推して理解できます。

メモリ セットの具体的な実装について詳しく説明します カード テーブル

カード テーブル

カード テーブルは、各要素のバイト配列 CARD_TABLE[] を使用して実装されます。識別されたメモリ領域は特定のサイズのメモリ ブロックです。各メモリ ブロックはカード ページと呼ばれます。ホットスポットで使用されるカード ページのサイズは 2^9、つまり 512 バイトです。以下の図に示すように、

#このようにして、カード ページに応じて特定の領域を分割することができます。新しい世代の領域をガベージ コレクションしたい場合は、次のようにすることができます。時代エリアは下図のようにカードページごとに分かれています。 Java ガベージ コレクションのメカニズムを理解する

Java ガベージ コレクションのメカニズムを理解する

図に示すように、cardpage1 には新しい世代を指す世代間参照があるため、対応するカード テーブルの最初の位置は 1 となり、カードページ 1 に新しい世代が存在することを示します。このページ領域オブジェクトの世代間アプリケーション。

  • カード テーブル アングル: page1 には世代を超えた飲酒オブジェクトがあるため、カード テーブルに対応する最初の位置は 1 として記録され、page1 要素がダーティであることを示します。

  • メモリ リサイクルの観点: カード テーブルの最初の位置は 1 であるため、ページ領域に世代を超えたアプリケーション オブジェクトがあり、この領域をスキャンする必要があることを示します。ゴミ収集。

カード ページのメモリには通常、複数のオブジェクトが含まれています。カード ページ内の 1 つ (または複数) のオブジェクトのフィールドに世代間ポインタがある限り、対応するカード テーブルは次のようになります。配列要素の値は 1 としてマークされます。これは、要素がダーティ (Dirty) であることを意味します。そうでない場合は、0 としてマークされます。ガベージ コレクションが発生すると、カード テーブル内のダーティ要素がフィルターで除外されている限り、どのカード ページ メモリ ブロックに世代間ポインタが含まれているかを簡単に見つけ出し、それらを GC ルートに追加して一緒にスキャンできます。これにより、古い世代全体をスキャンする必要がなくなり、GC ルートのスキャン範囲が大幅に減少します。

以上がJava ガベージ コレクションのメカニズムを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。