仮想マシンのガベージコレクションについて話す

最近、GeekTimeの「Java仮想マシンの徹底的な解体」クラスで勉強したので、研究ノートを記録し、関連する内容を考えて拡張しました。

1.オブジェクトが生きているか死んでいるかを区別する方法は?

識別には、参照カウントと到達可能性分析の2つの計算方法があります。

1.1参照カウント方法

実装:各オブジェクトに参照カウンターを追加して、オブジェクトを指す参照の数をカウントします。オブジェクトの参照カウンターが0になると、オブジェクトが停止し、リサイクルできることを意味します。

短所:
1。カウンターを格納するための追加のスペースが必要であり、面倒な更新操作が必要です

2.参照カウント方法には大きな抜け穴があります。つまり、循環参照オブジェクトを処理できません。

1.2アクセシビリティ分析

実装方法:これが主流のガベージコレクターです。このアルゴリズムの本質は、一連のGCルートを最初のライブセット(ライブセット)として取得し、セットから開始して、セットが参照できるすべてのオブジェクトを探索し、それらをセットに追加することです。プロセス、マークとも呼ばれます。結局、未踏のオブジェクトは死んでいて、回復することができます。

GCルートには次のものが含まれます(ただし、これらに限定されません)。

Javaメソッドスタックフレームのローカル変数。

ロードされたクラスの静的変数。

JNIハンドル;

開始され、停止されないJavaスレッド。

短所:たとえば、マルチスレッド環境では、他のスレッドがすでにアクセスされているオブジェクトの参照を更新し、誤検知(参照をnullに設定)または誤検知(未訪問のオブジェクトへの参照を設定)を引き起こす可能性があります。誤検知による害はなく、Java仮想マシンはガベージコレクションの機会をせいぜいいくつか失います。ガベージコレクタは、まだ参照されているオブジェクトのメモリを再利用する可能性があるため、誤ったレポートはさらに厄介です。リサイクルされたオブジェクトが元の参照からアクセスされると、Java仮想マシンが直接クラッシュする可能性があります。

2.この問題を解決するにはどうすればよいですか?

Java仮想マシンのStop-the-worldは、セーフポイントメカニズムを介して実装されます。Java仮想マシンは、Stop-the-world要求を受信すると、すべてのスレッドが安全なポイントに到達するのを待ってから、Stop-the-worldを要求するスレッドに排他的な作業を実行させます。そして、それをどのように詳細に実装するかは、一つ一つは言われません。要約すると、各メソッドでセーフポイントを呼び出してからメソッドを呼び出すか、メソッドを完了すると、セーフティポイントチェックがトリガーされます。セーフティポイントチェックでガベージコレクションを停止する必要があることが検出されると、スレッドが最初にブロックされます。そして、チェックのサイズはメソッドです。なぜすべてのバイトコードではないのか、主な問題はオーバーヘッドです。

3.ガベージコレクションを実行するにはどうすればよいですか?

生き残ったオブジェクトすべてにマークが付けられたら、死んだオブジェクトのリサイクルを進めることができます。主流の基本的なリサイクル方法は3つのタイプに分けることができます。

3.1クリア(スイープ)

実装:デッドオブジェクトが占有しているメモリを空きメモリとしてマークし、空きリストに記録します。新しいオブジェクトを作成する必要がある場合、メモリ管理モジュールは空きリストから空きメモリを探し、それを新しく作成されたオブジェクトに分割します。

短所:

1)メモリの断片化を引き起こします。Java仮想マシンのヒープ内のオブジェクトは継続的に分散する必要があるため、空きメモリの合計は十分であるが割り当てることができないという極端な状況が発生する可能性があります。

2)流通効率が低い。連続したメモリスペースの場合は、ポインタバンピングを介して割り当てることができます。空きリストの場合、Java仮想マシンは、リスト内の項目に1つずつアクセスして、新しく作成されたオブジェクトに入れることができる空きメモリを見つける必要があります。

3.2圧縮(コンパクト)

実装:生き残ったオブジェクトをメモリ領域の先頭に集め、連続したメモリ空間を残します。このアプローチは、メモリの断片化の問題を解決できます

短所:圧縮アルゴリズムのパフォーマンスオーバーヘッドが大きく、多数のオブジェクトを移行する必要があり、プロセスが多くのリソースと時間を消費します。

3.3コピー

実装:メモリ領域を2つの等しい部分に分割し、fromとtoの2つのポインタを使用してそれぞれを維持し、fromポインタが指すメモリ領域のみを使用してメモリを割り当てます。ガベージコレクションが発生すると、残っているオブジェクトがtoポインタが指すメモリ領域にコピーされ、fromポインタとtoポインタの内容が交換されます。このリサイクル方法をコピーすると、メモリの断片化の問題も解決できます。

短所:スペースの使用は非常に非効率的です。半分しか使用できず、通常は空であることを説明します。

4.JVMガベージコレクションの概要

Java仮想マシンは、世代ごとに異なるリサイクルアルゴリズムを使用できます。新世代の場合、ほとんどのJavaオブジェクトは短期間しか存続しないと推測されます。その後、短時間のガベージコレクションアルゴリズムを頻繁に使用して、ほとんどのガベージを新世代で収集できるようにすることができます。古い世代の場合、ごみのほとんどは若い世代で収集されており、古い世代のオブジェクトは存続する可能性が高いと考えられます。古い世代のコレクションが実際にトリガーされた場合、この仮定が間違っているか、ヒープスペースが使い果たされていることを意味します。

5.Java仮想マシンのヒープ分割

Java仮想マシンは、ヒープを新世代と旧世代に分割します。その中で、新世代はエデンエリアと同じサイズの2つのサバイバーエリアに分かれています。以下に示すように:

画像

デフォルトでは、Java仮想マシンは動的割り当て戦略(Java仮想マシンパラメータ-XX:+ UsePSAdaptiveSurvivorSizePolicyに対応)を採用します。これは、生成されたオブジェクトの割合と使用量に応じて、Eden領域とSurvivor領域の比率を動的に調整します。サバイバーエリアの。

-XX:SurvivorRatioは、この比率を修正します。ただし、サバイバー領域の1つは常に空になるため、比率が低いほど、無駄なヒープスペースが多くなることに注意してください。

6.ガベージコレクションのメカニズム

6.1マイナーGC

マイナーGCがトリガーされたとき、エデン領域がいっぱいになったとき、マークコピーアルゴリズムをどのように処理しますか?以下のフローチャートを参照してください。

画像

上記の各判断には、実際には構成および設定できるパラメーターがありますが、ここでは省略しています。

GCのマイナーな利点:

1)エデンエリアのオブジェクトは、基本的に1回の使用でクリアされるため、残っているオブジェクトのみをコピー用にマークする必要があります。実際、クリアは非常に効率的です。

2)ヒープ全体をガベージコレクションする必要はありません。それは非常に効率的な新世代をきれいにするだけです。

問題:

つまり、古い世代のオブジェクトは、新しい世代のオブジェクトを参照する場合があります。言い換えれば、生きているオブジェクトをマークするとき、私たちは古い時代のオブジェクトをスキャンする必要があります。オブジェクトに新世代オブジェクトへの参照がある場合、この参照はGCルートとしても使用されます。そのため、フルGCの概念が導入されました。

6.2フルGC

フルトリガータイミング:オブジェクトがオールドエイジに昇格したときに、オールドエイジが不十分またはスペースが不足していることが検出された場合にトリガーされます。恒久的な生成のための不十分なスペース。または、オブジェクトが永続世代で作成され、メモリが不足していることが判明したが、通常の永続世代がシステムメモリにあるため、通常はメモリ不足が少なくなります。

実装プロセス:さまざまなガベージコレクターがさまざまなアルゴリズムを使用します。主なプロセスは、古い時代のオブジェクトを作成し、メモリが不足していることを確認することです。その後、到達できない領域のオブジェクトをリサイクルします。リカバリ後、メモリの場合まだ不十分で、オブジェクトを保存できません。今回はエラーメモリリークが報告されます。

通常、完全なgcを送信することはプログラムにとって重大な警告であり、完全なgcを一緒に変更するいくつかの動作を防ぎ、それによってシステムの正常な動作を保証するために、より注意が払われます。

7.ガベージコレクター

一般的なガベージコレクター:シリアルGC、ParNew GC、Parrallel GC、CMS GC、G1 GC

7.1シリアルGC

最古のガベージコレクターであり、収集作業に反映されている「シリアル」はシングルスレッドであり、ガベージコレクションの過程で悪名高い「Stop-The-World」状態になります。もちろん、そのシングルスレッド設計は、合理化されたGC実装、複雑なデータ構造を維持する必要がないこと、および単純な初期化を意味するため、クライアントモードのJVMのデフォルトオプションとして常に使用されてきました。

7.2 ParNew GC

これは新世代のGC実装であり、実際にはシリアルGCのマルチスレッドバージョンです。最も一般的なアプリケーションシナリオは、古いCMSGCを使用することです。

7.3パラレルGC

これは、サーバーモードJVMのデフォルトのGC選択であり、スループットファーストGCとも呼ばれます。そのアルゴリズムはシリアルGCに似ていますが、実装ははるかに複雑ですが、その特徴は、新世代と旧世代のGCが並行して実行されることです。これは、一般的なサーバー環境でより効率的です。

7.4 CMS GC

Mark-Sweepアルゴリズムに基づく設計目標は、一時停止時間を最小限に抑えることです。これは、Webなどの応答時間に敏感なアプリケーションにとって非常に重要です。今日でも、多くのシステムでCMSGCが使用されています。ただし、CMSで採用されているマークアンドスイープアルゴリズムにはメモリの断片化の問題があるため、長期間の操作などの条件下で完全なGCの発生を回避することは困難であり、一時停止が悪くなります。さらに、コンカレントが強調されているため、CMSはより多くのCPUリソースを使用し、ユーザースレッドと競合します。CMSは、JDK9で非推奨としてマークされています

7.5 G1 GC

G1 GCこれは、スループットと一時停止時間を考慮したGC実装です。これは、Oracle JDK9以降のデフォルトのGCオプションです。G1は、一時停止時間の目標を直感的に設定できます。CMSGCと比較すると、G1はCMSを遅らせることができない場合がありますが、最悪の場合ははるかに優れています。したがって、多くの場合、サーバーのガベージコレクターとしてG1GCを選択することをお勧めします。それで、ここにC1GCの詳細な紹介があります。

7.5.1まず、GC1の基本的な理解

リージョン:G1の各世代のストレージアドレスは不連続です。各世代は同じサイズのn個の不連続リージョンを使用し、各リージョンは連続した仮想メモリアドレスを占有します。

以下に示すように:

画像

G1のメモリ構造は、従来の構造とは異なるだけでなく、図のHである従来のモジュールよりも構造モジュールが1つ多いことがわかります。そのフルネームはHumongousで、文字通り巨大を意味します。これらのリージョンは、巨大なオブジェクトを格納するために使用されます。つまり、オブジェクトのサイズが特定のしきい値を超えると、Humongousとしてマークされます。私たちの伝統によれば、そのような大きなオブジェクトは、古い世代に直接配置されます。

RSet:このリージョンへのすべての外部参照を記録するために使用されるフルネームの記憶セット。各リージョンはRSetを維持します。このような記録方法を使用する利点は、リージョンを再利用するときにフルヒープスキャンを実行する必要がなく、RSをチェックするだけで外部参照を見つけることができることです。これらの参照は、最初のマークのルートの1つです。 。

カード: JVMはメモリを固定サイズのカードに分割します。ここでは、物理メモリ上のページの概念を比較できます。

カードテーブル:スレッドがリージョン内の参照を変更する場合、レコードを変更するようにRSに通知する必要があります。この目標を達成するために、G1コレクターは新しい構造であるCT(カードテーブル)-カードテーブルを導入します。各カードはバイトを使用して、変更されたかどうかを記録します。カードテーブルは、これらのバイトのコレクションです。

リージョン、カード、カードテーブル、およびRsetの関係は次のとおりです。

画像

7.5.2 C1GCモード

主に含まれるもの:ヤングGC、混合GC、フルGC。
エデンエリアのメモリが不足すると、ヤングGCが発生します。ヒープサイズ全体に占める老齢の割合がしきい値に達すると、混合GCが発生します。また、G1のガベージコレクションプロセスがアプリケーションと同時に実行される場合、Mixed GCの速度がメモリのアプリケーションの速度に追いつかない場合、MixedG1はシリアルGCを使用してフルGCにダウングレードされます。

これが混合GCについての詳細な話です。

  1. 混合GCとは何ですか?
    若い世代のすべての領域と古い世代の一部の領域を再利用します。古い世代のリサイクル部分は、G1収集プロセスのターゲット一時停止時間を指定するために使用されるパラメーター-XX:MaxGCPauseMillisです。デフォルト値は200msです。もちろん、これは単なる期待値です。G1の威力は、一時停止予測モデル(一時停止予測モデル)を備えていることです。一時停止時間を満たすために、いくつかの領域を選択的に選択します。

  2. 混合GCのトリガー条件は何ですか?
    混合GCのトリガーも、いくつかのパラメーターによって制御されます。たとえば、XX:InitiatingHeapOccupancyPercentは、ヒープサイズ全体に対する老齢の割合を表します。デフォルト値は45%です。このしきい値に達すると、混合GCがトリガーされます。

  3. 混合GCのプロセスは何ですか?
    混合GCは、2つの段階に分けることができます。
    グローバル並行マーキング
    グローバル並行マーキングは、次のように5つの段階に分けることができます。
    初期マーキング:GCルートから直接到達可能なオブジェクトにマーキングします。最初のマーキングフェーズは若いGCの一時停止を借用するため、追加の個別の一時停止フェーズはありません。
    同時マーキング:この段階では、ヒープ内のオブジェクトがGCルートからマーキングされ、マーキングスレッドがアプリケーションスレッドと並行して実行され、各リージョンのライブオブジェクト情報が収集されます。
    最終マーク:同時マークフェーズ中に変更され、リサイクルされるオブジェクトにマークを付けます。
    ガベージの削除:この段階でライブオブジェクトのないリージョンが見つかった場合、割り当て可能なリージョンのリストに全体として再利用されます。空の領域をクリアします。
    ライブオブジェクト
    コピーの退避フェーズは完全に中断されます。リージョン内のライブオブジェクトの一部を空のリージョンにコピーし(並列コピー)、元のリージョンスペースを再利用します。避難フェーズでは、任意の数のリージョンを自由に選択して、コレクションセット(コレクションセット、略してCSet)を個別に収集および形成できます。CSetコレクションでのリージョンの選択は、上記の一時停止予測モデルによって異なります。この段階すべての生物を避難させるわけではありません。避難する収入の多い地域をいくつか選択するだけで、この停止のオーバーヘッドを(特定の範囲内で)制御できます。

  4. 混合GCの効果は何ですか?
    混合GCは、主に古い領域の不要なオブジェクトを早期にクリーンアップしてリサイクルし、不要なオブジェクトのバックログを減らし、完全なGCを引き起こし、オブジェクトプログラムを一時停止させます。

記事を学んでいただきありがとうございます:

1.ガベージコレクションとは何ですか?

2. Java Hotspot G1GCのいくつかの主要テクノロジー

3.エントリーからあきらめるまでのG1

4.G1ガベージコレクションの詳細な説明

5.オタクタイムクラス-「Java仮想マシンの詳細な逆アセンブル」

おすすめ

転載: blog.csdn.net/vipshop_fin_dev/article/details/108039608