ホームページ  >  記事  >  Java  >  Java の仮想マシンのガベージ コレクション メカニズムの詳細な図とテキストの説明

Java の仮想マシンのガベージ コレクション メカニズムの詳細な図とテキストの説明

黄舟
黄舟オリジナル
2017-08-09 09:31:531281ブラウズ

Java 仮想マシンでは、オブジェクトと配列のメモリがヒープに割り当てられ、ガベージ コレクターによって回復されたメイン メモリはヒープ メモリにあります。 Java プログラムの実行中に動的に作成されたオブジェクトまたは配列が時間内にリサイクルされずに蓄積し続けると、最終的にはヒープ メモリがいっぱいになり、OOM が発生します。

JVM は、GC メカニズムと呼ばれるガベージ コレクション メカニズムを提供します。 GC メカニズムを通じて、ヒープ内のガベージ オブジェクトを動作中に継続的にリサイクルできるため、プログラムの正常な動作が保証されます。

ガベージ オブジェクトの決定

いわゆる「ガベージ」オブジェクトとは、プログラムの実行中に役に立たなくなったオブジェクト、つまり、もはや生きていないオブジェクトを指すことは誰もが知っています。では、ヒープ内のオブジェクトが「ゴミ」なのか、それとももう生きていないオブジェクトなのかをどのように判断するのでしょうか?

参照カウント方法

各オブジェクトには参照カウント属性があり、オブジェクトが参照された回数を保存するために使用されます。参照数が0の場合は、そのオブジェクトが参照されていないことを意味し、そのオブジェクトは使用されず、ゴミオブジェクトと判断できる。しかし、この方法には大きなバグがあります。それは、オブジェクト間の相互参照や循環参照の問題を解決できないことです。2 つのオブジェクトが相互に参照する場合、それらは他のオブジェクトと参照関係を持たず、同じ番号を持ちます。の参照は 0 ではないため、リサイクルされませんが、実際には、これら 2 つのオブジェクトは役に立ちません。

到達可能性解析(ルート探索法)

参照カウントの使用によって引き起こされる問題を回避するために、Java は到達可能性解析方法を使用してガベージオブジェクトを特定します。

このメソッドは、すべてのオブジェクトの参照関係をツリーとして想像できます。ツリーのルート ノード GC ルートから、ツリーのすべての参照オブジェクトは到達可能なオブジェクトであり、そのノードにない他のオブジェクトもトラバースされます。は到達不可能なオブジェクトです。

では、GC のルートノードとして使用できるオブジェクトはどのようなものでしょうか?

  • 仮想マシンスタックで参照されるオブジェクト(フレームスタックのローカル変数テーブル)

  • メソッド領域の静的プロパティによって参照されるオブジェクト

  • メソッド領域の定数によって参照されるオブジェクト

  • ローカルメソッド スタック JNI によって参照されるオブジェクト

参照ステータス

ガベージ コレクション メカニズムは、参照カウントであっても到達可能性分析であっても、オブジェクトの参照に関連しています。

  • 強力な参照状態があります。参考資料 - 私たちが使用する参考資料のほとんどは実際には強力な参考資料であり、これが最も一般的に使用される参考資料です。オブジェクトに強参照がある場合、それは到達可能な状態にあることを意味し、システム メモリが非常に不足している場合でも、Java 仮想マシンはエラーをスローしてプログラムを終了させます。参照されたオブジェクトへの参照が異常にリサイクルされる。したがって、強参照は Java メモリ リークの主な原因の 1 つです。 OutOfMemoryError

  • ソフト参照 - オブジェクトにはソフト参照のみがあり、メモリ空間が十分な場合、ガベージ コレクターはそれを再利用しません。メモリ空間が不十分な場合、これらのオブジェクトのメモリは再利用されます。ガベージ コレクターがオブジェクトを収集しない限り、オブジェクトはプログラムで使用できます。

  • 弱参照 - オブジェクトには弱参照のみがあり、これは不要であることに似ています。弱参照はソフト参照に似ていますが、参照レベルが低くなります。弱参照とソフト参照の違いは、弱参照のみを持つオブジェクトのライフサイクルが短いことです。ガベージ コレクター スレッドがその管轄下のメモリ領域をスキャンするプロセス中に、弱い参照のみを持つオブジェクトが見つかると、現在のメモリ領域が十分であるかどうかに関係なく、そのメモリが再利用されます。

  • ダミー参照 - オブジェクトはファントム参照のみを保持します。その場合、参照がないのと同じであり、いつでもガベージ コレクターによってリサイクルされる可能性があります。仮想参照は主に、ガベージ コレクションされるオブジェクトのアクティビティを追跡するために使用されますが、通常は使用しません。

ガベージコレクションアルゴリズム

到達可能性分析アルゴリズムを通じて、どのオブジェクトをリサイクルする必要があるかを判断できます。では、リサイクルはどのように実行する必要があるのでしょうか?

マーククリアアルゴリズム

まず、リサイクル可能なオブジェクトメモリをマークし、次にリサイクルされたメモリをクリアする必要があります。

マークアンドクリアアルゴリズム (リサイクル前)

マークアンドクリアアルゴリズム (リサイクル後)

ただし、この場合、プログラムの実行中にメモリの割り当てと解放が継続的に行われます。その多くはヒープ内に生成され、不連続な空きメモリ領域、つまりメモリの断片化が発生します。このように、十分な空きメモリがあっても、十分な大きさのメモリを割り当てることができない可能性があり、頻繁に GC が発生して効率に影響を与えたり、OOM にさえ影響したりする可能性があります。

Mark-Compact アルゴリズム

Mark-Clear アルゴリズムとは異なり、Mark-Compact アルゴリズムは、マーク付け後に再利用可能なメモリを直接クリーンアップしません。代わりに、残っているすべてのオブジェクトを一方の端に移動してから、再利用可能なメモリを消去します。

マーキング - 照合アルゴリズム (リサイクル前)

マーキング - 照合アルゴリズム (リサイクル後)

この利点は、メモリの断片化が発生しないことです。

コピー アルゴリズム

コピー アルゴリズムでは、まずメモリを 2 つのブロックに分割し、最初にメモリ ブロックの 1 つにメモリを割り当てる必要があります。このメモリ ブロックが割り当てられると、ガベージ コレクションが実行され、その後、存続するすべてのオブジェクトがコピーされます。メモリの他のブロックがオンになると、メモリの最初のブロックが完全にクリアされます。

コピーアルゴリズム(リサイクル前)

コピーアルゴリズム(リサイクル後)

このアルゴリズムはメモリの断片化を引き起こしませんが、メモリ空間の半分しか使用しないことと同等です。同時に、レプリケーション アルゴリズムは生き残るオブジェクトの数に関係します。生き残るオブジェクトの数が多い場合、レプリケーション アルゴリズムの効率は大幅に低下します。

世代別コレクション アルゴリズム

Java 仮想マシンでは、オブジェクトのライフ サイクルが長い場合もあれば、短い場合もあります。ほとんどのオブジェクトは、少数のオブジェクトのみが長期間メモリに残るため、オブジェクトの存続期間の長さによって、オブジェクトはさまざまな領域に配置されます。世代別コレクション アルゴリズムを使用する Java 仮想マシン ヒープでは、通常、次の 3 種類のオブジェクトを保存するために 3 つの領域に分割されます:

  • 新しい世代 - 新しく作成されたオブジェクトは、通常、コードの実行中に収集され続けます。新しいオブジェクトを作成します。これらの新しく作成されたオブジェクトの多くはローカル変数であり、すぐにガベージ オブジェクトになります。これらのオブジェクトは、若い世代と呼ばれるメモリ領域に配置されます。新しい世代は、多くのゴミオブジェクトと少数の生き残ったオブジェクトによって特徴付けられます。

  • 古い世代 - 一部のオブジェクトは非常に初期に作成され、多くの GC の後もリサイクルされませんでしたが、常に生き残っています。これらのオブジェクトは、旧世代と呼ばれる領域に配置されます。旧世代の特徴は、生き残ったオブジェクトが多く、ゴミオブジェクトが少ないことです。

  • 永続世代 - 静的オブジェクトや定数など、仮想マシンのライフサイクルとともに永続的に存在するオブジェクト。これらのオブジェクトは、永続世代と呼ばれる領域に配置されます。永続世代の特徴は、これらのオブジェクトは通常、ガベージ コレクションを必要とせず、仮想マシンの実行中も存続することです。 (Java 1.7 より前では、永続世代オブジェクトはメソッド領域に格納されていました。Java 1.7 メソッド領域の永続世代オブジェクトはヒープに移動されました。Java 1.8 では、永続世代オブジェクトはヒープから削除されました。このメモリは)

世代別コレクション アルゴリズムは、新しい世代と古い世代に基づいてガベージ コレクションも実行します。

新世代領域では、GC ごとに多くのガベージ オブジェクトがリサイクルされ、生き残るのはほんのわずかです。したがって、コピー リサイクル アルゴリズムが使用され、わずかに残ったオブジェクトは GC 中にコピーできます。

新世代エリアでは、コピーとリサイクルが1:1の比率で行われるのではなく、8:1:1の比率でEden、SurvivorA、SurvivorBの3つのエリアに分かれています。 Eden はエデンの園を意味し、そこで作成された多くの新しいオブジェクトを表します。Survivor 領域は生存者、つまり GC 後に生き残ったオブジェクトを指します。

  1. Eden 領域は、ヒープ メモリを外部の世界に提供します。 Eden 領域がほぼ満杯になると、マイナー GC (新世代 GC) が実行され、残ったオブジェクトが SurvivorA 領域に配置され、Eden 領域がクリアされます

  2. Eden 領域がクリアされた後、ヒープを提供し続けます。

  3. Eden 領域が再び埋まると、このとき、Eden 領域と SurvivorA 領域に対して同時にマイナー GC (新世代 GC) が実行され、残ったオブジェクトが配置されます。このとき、Eden 領域と SurvivorA 領域は同時にクリアされます。

  4. Eden 領域がいっぱいになった後、ヒープメモリを外部に提供し、上記のプロセスを繰り返します。 、エデンエリアとサバイバーエリアに残っているオブジェクトは、別のサバイバーエリアに配置されます

  5. サバイバーエリアがいっぱいになったとき、およびコピーされていないオブジェクトがまだあるとき、またはいくつかのオブジェクトが生き残ったとき。 15 回、これらの残りのオブジェクトは旧世代領域に配置され、旧世代領域もいっぱいになると、メジャー GC (旧世代 GC) が実行され、旧世代領域に対してガベージ コレクションが実行されます。

一般に、古い世代領域のオブジェクトは各 GC 中に生存期間が長く、より多くの生存オブジェクトが存在するため、マークアンド整理アルゴリズムを使用して、GC 中にメモリを消費せずに少数の生存オブジェクトを移動します。断片化。

GC トリガーの種類

Java 仮想マシンは各 GC トリガーの情報を出力し、ログに基づいて GC がトリガーされた理由を分析できます。

  • GC_FOR_MALLOC: ヒープ上にオブジェクトを割り当てるときにメモリ不足によって GC がトリガーされることを示します。

  • GC_CONCURRENT: アプリケーションのヒープ メモリが一定量に達するか、ほぼいっぱいであると認識されると、システムは自動的に GC 操作をトリガーしてメモリを解放します。

  • GC_EXPLICIT: アプリケーションが System.gc、VMRuntime.gc インターフェイスを呼び出すか、SIGUSR1 シグナルを受信したときに GC がトリガーされることを示します。

  • GC_BEFORE_OOM: OOM 例外をスローする準備をする前の最後の作業によって GC がトリガーされることを示します。

以上がJava の仮想マシンのガベージ コレクション メカニズムの詳細な図とテキストの説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。