JVM メモリ管理について話す [非専門家]

JVM メモリ管理について話す [非専門家]

[[399153]]

JVM メモリレイアウト

1 つのタイプは各スレッド専用です。

  1. PC レジスタ: プログラム カウンターとも呼ばれ、各スレッドで現在実行されている命令情報を記録します (例: 現在実行されている命令と次に実行される命令)
  2. JVM スタック: 仮想マシン スタックとも呼ばれ、各スタック フレームにローカル変数、メソッドの戻りアドレスなどを記録します。スレッド内でメソッドが呼び出されるたびに、フレームが作成され、メソッド呼び出しが終了すると破棄されます。
  3. ネイティブ メソッド スタック: ローカル メソッド スタックは、その名前が示すように、オペレーティング システムのネイティブ メソッドを呼び出すときに必要なメモリ領域です。

上記 3 種類の領域のライフサイクルは、スレッドの場合と同じで、スレッドが作成されると対応するメモリ領域が作成され、スレッドが破棄されると対応するメモリが解放されます。

  • ヒープ: これは有名なヒープ メモリ領域であり、GC ガベージ コレクションの主要な場所でもあります。クラスインスタンスオブジェクトや配列インスタンスなどを格納するために使用されます。

注: ヒープはすべてのスレッドで共有されます。文言を厳密に解釈すると、これは完全に正しいとは言えません。実際、TLAB の存在により、同時オブジェクト割り当て時に複数のオブジェクトが同じメモリ ブロックに割り当てられるのを防ぐために、割り当て時にヒープ内の TLAB 領域がスレッドによって排他的に書き込まれます。

  • メソッド領域: メソッド領域には、主にクラス構造、クラス メンバー定義、静的メンバーなどが格納されます。
  • ランタイム定数プール: 文字列、-128 ~ 127 の範囲の int 値などのランタイム定数プール。メソッド領域の一部です。

ヒープとメソッド領域は、仮想マシンの起動時に作成され、仮想マシンの終了時に解放されます。

どのメモリ領域に GC が必要ですか?

スレッド専用の領域: PC レジストリ、JVM スタック、ネイティブ メソッド スタック。これらのライフ サイクルはスレッドと同じです (つまり、スレッドと共に存続し、消滅します) ので、GC は必要ありません。スレッドによって共有されるヒープ領域とメソッド領域が GC の焦点となります。

参照タイプ

強い参照: 強い参照に関連付けられたオブジェクトはリサイクルされません。

ソフト参照: ソフト参照に関連付けられたオブジェクトは、メモリが不足している場合にのみリサイクルされます。

弱参照: 弱参照に関連付けられたオブジェクトは確実にリサイクルされます。つまり、次のガベージ コレクションが発生するまでしか存続できません。

ファントム参照: オブジェクトにファントム参照を設定する唯一の目的は、オブジェクトがリサイクルされたときにシステム通知を受信することです。

マイナーGCとフルGC

マイナー GC: 新しい世代を取り戻します。新世代のオブジェクトの寿命は短いため、マイナー GC は頻繁に実行され、通常はより高速に実行されます。

マイナー GC のトリガー条件は非常に単純です。 Eden スペースがいっぱいになると、マイナー GC がトリガーされます。

フル GC: 古い世代と新しい世代を再利用します。古い世代のオブジェクトは生存時間が長いため、Full GC はほとんど実行されず、実行速度は Minor GC よりもはるかに遅くなります。

FULL GC のトリガー条件は次のとおりです。

System.gc() の呼び出し

これは、仮想マシンが Full GC を実行することを示唆するだけですが、仮想マシンが実際にそれを実行しない可能性があります。この方法を使用することはお勧めしません。代わりに、仮想マシンにメモリを管理させます。

「旧世代のスペースが不足しています」

古い世代に十分なスペースがない一般的なシナリオとしては、上記の大きなオブジェクトが古い世代に直接入る場合や、長期間存続するオブジェクトが古い世代に入る場合などが挙げられます。

上記の理由により発生する Full GC を回避するには、1. 大きすぎるオブジェクトや配列を作成しないようにしてください。 2. さらに、-Xmn 仮想マシン パラメータを使用して新しい世代のサイズを増やすことで、オブジェクトが可能な限り新しい世代でリサイクルされ、古い世代に入らないようにすることができます。 3. -XX:MaxTenuringThreshold を使用して、古い世代に入るオブジェクトの年齢を増やし、オブジェクトが新しい世代でより長い期間存続できるようにすることもできます。

「スペース割り当ての保証に失敗しました」

コピーアルゴリズムを使用するマイナー GC では、保証として古い世代のメモリ空間が必要です。保証が失敗した場合、Full GC が実行されます。

「JDK 1.7 以前では永続的な世代スペースが不足しています」

JDK 1.7 以前では、HotSpot 仮想マシンのメソッド領域は、一部のクラス情報、定数、静的変数、およびその他のデータを格納する永続世代を使用して実装されていました。

システム内にロードするクラス、反映するクラス、呼び出されるメソッドが多数ある場合、永続世代がいっぱいになる可能性があり、CMS GC が構成されていない場合でも Full GC が実行されます。フル GC 後もメモリを回復できない場合、仮想マシンは java.lang.OutOfMemoryError をスローします。

上記の理由により発生する Full GC を回避するには、永続的な生成領域を増やすか、CMS GC に切り替えることができます。

「同時モードの失敗」

CMS GC の実行中に、同時に古い世代に配置するオブジェクトがあり、古い世代に十分なスペースがない場合 (GC プロセス中に浮遊するガベージが多すぎて、一時的にスペースが不足する場合があります)、同時モード障害エラーが報告され、フル GC がトリガーされます。

物体がゴミかどうかを判断する方法

参照カウントアルゴリズム

2 つのオブジェクト間に循環参照がある場合、参照カウンターは 0 になることはなく、それらをリサイクルすることは不可能になります。循環参照が存在するため、Java 仮想マシンは参照カウント アルゴリズムを使用しません。

  • 到達可能性分析アルゴリズム

検索はGC Rootsから始まります。到達可能なオブジェクトはすべて有効であり、到達不可能なオブジェクトはリサイクルできます。

Java 仮想マシンはこのアルゴリズムを使用して、オブジェクトがリサイクル可能かどうかを判断します。 GC ルートには通常、次のものが含まれます。

  • 仮想マシンスタック内のローカル変数テーブルで参照されるオブジェクト
  • ネイティブメソッドスタック内のJNIで参照されるオブジェクト
  • メソッド領域内のクラスの静的属性によって参照されるオブジェクト
  • メソッド領域内の定数によって参照されるオブジェクト

オブジェクトのリサイクルに加えて、クラスのアンロードも行われる可能性がある。

方法領域には主に永久世代オブジェクトが保管されており、永久世代オブジェクトの回収率は新世代の回収率よりもはるかに低いため、方法領域でのリサイクルは費用対効果が高くありません。メソッド領域のリサイクルには、主に定数プールのリサイクルとクラスのアンロードが含まれます。

メモリ オーバーフローを回避するために、リフレクションと動的プロキシが広範囲に使用されるシナリオでは、仮想マシンにクラス アンロード機能が必要です。クラスをアンインストールするには多くの条件があります。以下の 3 つの条件を満たす必要があり、条件を満たしていてもクラスをアンインストールすることはできません。

  • このクラスのインスタンスはすべてリサイクルされており、現時点ではヒープ内にこのクラスのインスタンスは存在しません。
  • このクラスをロードした ClassLoader はリサイクルされました。
  • このクラスに対応する Class オブジェクトはどこからも参照されていないため、クラス メソッドはどこからもリフレクションを通じてアクセスできません。

ファイナライズ()

  • C++ デストラクタと同様に、外部リソースを閉じるために使用されます。ただし、try-finally などのメソッドの方が優れている可能性があり、このメソッドは実行コストが非常に高く、不確実性が大きく、各オブジェクトの呼び出し順序を保証できないため、使用しない方がよいでしょう。
  • オブジェクトがリサイクル可能な場合、オブジェクトの finalize() メソッドを実行する必要がある場合、このメソッド内でオブジェクトを再度参照させることで、自己救済を実現できます。セルフレスキューは1回のみ実行できます。リサイクルされたオブジェクトが以前に自己修復のために finalize() メソッドを呼び出した場合、その後のリサイクル中にそのメソッドは再度呼び出されません。

よく使われるGCアルゴリズム

「マーク アンド スイープ方式」: マーキング フェーズでは、プログラムは各オブジェクトがアクティブ オブジェクトであるかどうかを確認します。アクティブなオブジェクトの場合、プログラムはオブジェクト ヘッダーをマークします。

クリアフェーズでは、オブジェクトはリサイクルされ、フラグはキャンセルされます。さらに、リサイクルされたブロックが前の空きブロックと連続しているかどうかが判断されます。そうであれば、2 つのブロックが結合されます。オブジェクトのリサイクルとは、オブジェクトをブロックとして「フリー リスト」と呼ばれる一方向のリンク リストに接続することを意味します。後で割り当てるときには、空きリストを走査してブロックを見つけるだけで済みます。

長所と短所:

  • マーキングとスイープのプロセスはあまり効率的ではありません。
  • 不連続なメモリフラグメントが大量に生成され、大きなオブジェクトにメモリを割り当てることができなくなります。

「マークコピー方式」:考え方も非常にシンプルです。メモリを半分に分割し、常に 1 つの部分を空のままにして (上の図の右側)、左側の残っているオブジェクト (薄い灰色の領域) を右側にコピーしてから、左側をクリアします。

長所と短所:

  • メモリの断片化の問題を回避します。
  • メモリの浪費は非常に深刻で、使用されているメモリの 50% に相当します。

現在の商用仮想マシンはすべて、この収集アルゴリズムを使用して新しい世代をリサイクルしますが、2 つの同じサイズのブロックに分割されるわけではありません。代わりに、より大きなエデン スペースと 2 つのより小さなサバイバー スペースに分割され、毎回エデンとサバイバー スペースの 1 つが使用されます。リサイクル中、Eden と Survivor 内の生き残ったオブジェクトはすべて別の Survivor にコピーされ、最後に Eden と使用済みの Survivor がクリーンアップされます。

HotSpot 仮想マシンの Eden と Survivor のサイズのデフォルト比率は 8:1 であり、メモリ使用率が 90% に達することが保証されます。各コレクションで 10% を超えるオブジェクトが生き残る場合、Survivor ブロックでは不十分です。この場合、スペース割り当ての保証のために古い世代に依存する必要があります。つまり、配置できないオブジェクトを格納するために古い世代のスペースを借りる必要があります。

Mark-Compact (Mark-Compress とも呼ばれる) 方式: 上記の 2 つのアルゴリズムの欠点を回避します。ガベージ オブジェクトをクリーンアップした後、残りのライブ オブジェクトは並べ替えられ、移動されます (Windows のディスクのデフラグと同様)。これにより、占有するスペースが連続的になり、メモリの断片化の問題が回避されます。ただし、ソート処理によって GC の効率も低下します。

「generation-collect 世代別コレクション アルゴリズム」: 実際に多くの分析を行った結果、メモリ内のオブジェクトは、ローカル変数/一時オブジェクトなどのようにライフサイクルが短いものもあれば、長期間存続するもの (通常は、Websocket の長い接続内の接続オブジェクトなど) など、大まかに 2 つのカテゴリに分類できることがわかりました。基本的な考え方は、メモリを若い世代、古い世代、永久世代の 3 つの主要なブロックに分割することです。若い世代はさらに、エデン、S0、S1 の 3 つの領域に分かれています。

最初は、eden 領域にオブジェクトが割り当てられており、s0 領域と s1 領域はほぼ空です。 Eden 領域がいっぱいになると、マイナー GC (ヤング GC とも呼ばれる) が発生します。最初のステップは、もちろん、到達不可能なガベージ オブジェクトを識別し、到達可能なオブジェクトを s0 領域に移動することです。その後、Eden 領域が再びいっぱいになると、S0 領域と Eden 領域にあるすべての到達可能なオブジェクトが S1 領域に移動されます。その後、領域 s0 と s1 のオブジェクトは前後に移動し、移動するたびに年齢が 1 増加します。したがって、年齢が一定の範囲に達すると、古い世代に移動されます。古い世代もいっぱいになった場合は、永久世代に移動されます。

  • 新世代の用途: コピーアルゴリズム
  • 旧世代では、マークスイープまたはマークコンパクトアルゴリズムを使用します。

ガベージコレクター

https://www.jianshu.com/p/b572f69a1b93

**新世代のガベージ コレクターは、Serial、ParNew、Parallel Scavenge、および G1 です。旧世代のガベージ コレクターは、CMS、Serial Old、Parallel Old、および G1 です。 **G1 は、新世代のオブジェクトと旧世代のオブジェクトの両方をリサイクルできるガベージ コレクターです。ただし、すべてのガベージ コレクターの中で普遍的に使用されているガベージ コレクターは存在しません。さまざまなシナリオにおいて、各ガベージ コレクターには、以下に示すように独自の利点があります。

  • 「シリアルコレクター」

**シングルスレッドのガベージ コレクター**。つまり、ガベージ コレクションを実行している間は、他のスレッドを一時停止する必要があります。

収集プロセス: すべてのスレッドを一時停止 アルゴリズム: コピーアルゴリズム 利点: シンプルで効率的、シングルスレッドの収集効率が高い アプリケーション: クライアントモードでのデフォルトの新世代コレクター

  • パーニューコレクター

これは、**Serial コレクターのマルチスレッド バージョンとして理解されます。スレッド切り替えのオーバーヘッドのため、**ParNew は単一 CPU 環境では Serial ほど優れていません (ParNew コレクション スレッドの数は CPU の数と同じなので、CPU が多すぎる環境では、-XX:ParallelGCThreads パラメータを使用して GC スレッドの数を制御できます)。

収集プロセス: すべてのスレッドを一時停止します。アルゴリズム: コピー アルゴリズム。利点: CPU が多数ある場合、シリアルよりも効果があります。シリアルは単一 CPU 環境でより適切に動作します。アプリケーション: サーバー モードで実行されている多くの仮想マシンで推奨される新世代のコレクター。

  • 「パラレル スカベンジ コレクター」

ParNew コレクターと同様に、Parallel コレクターはシステムのスループットに重点を置いています。 **違いは、Parallel Scavenge コレクターは制御可能なスループットに重点を置いていることです (「スループット = ユーザー コードの実行時間 / (ユーザー コードの実行時間 + ガベージ コレクション時間)」)。スループットが高ければ高いほど、ガベージ コレクションの時間が短くなり、ユーザー コードは CPU リソースを最大限に活用して、プログラムの計算タスクをできるだけ早く完了できます。

-XX:MaxGCPauseMillis はガベージ コレクションの最大一時停止時間を制御し、-XX:GCRatio はスループット サイズを直接設定します。

-XX:+UseAdaptiveSizePocily は、一時停止時間または最大スループットを動的に調整するために使用されます。この方法は GC 適応調整戦略と呼ばれ、ParNew コレクターでは使用できません。

  • 「シリアルオールドコレクター」

Serial Old コレクターは、Serial コレクターの旧世代バージョンです。これは、リサイクルに「マークスイープアルゴリズム」を使用するシングルスレッドコレクターでもあります。操作手順はシリアルコレクターと同じです。

  • 「パラレルオールドコレクター」

Parallel Old コレクターは、マルチスレッドと「マークスイープ」アルゴリズムを使用してガベージ コレクションを実行する Parallel Scavenge コレクターの古いバージョンです。

通常は、Parallel Scavenge コレクターと組み合わせて使用​​されます。 「スループット優先」コレクターがこの組み合わせの特徴です。この組み合わせは、スループットが重要で、CPU リソースが敏感な状況で使用できます。

  • 「CMSコレクター」

CMS (Concurrent Mark Sweep) コレクターは、コレクションの一時停止時間を最小限に抑えることを目的としたコレクターです。現在、多数の Java アプリケーションがインターネット サイトや B/S システムのサーバー側に集中しています。このようなアプリケーションは、サービスの応答速度に特に注意を払い、システムのダウンタイムを最小限に抑えてユーザーに優れたエクスペリエンスを提供することを期待しています。

「マークアンドスイープ」アルゴリズムに基づいており、その操作プロセスは以前のコレクターよりも複雑です。全体のプロセスは次の 4 つのステップに分かれています。

このうち、最初のマーキングと再マーキングの手順では、依然として「Stop The World」が必要です。 **初期マーキングでは、GC ルートに直接関連付けることができるオブジェクトのみがマークされるため、非常に高速です。同時マーキングフェーズは GC ルート トレースのプロセスであり、再マーキングフェーズは同時マーキング中にユーザー プログラムが継続的に動作したためにマーキングが変更されたオブジェクトのマーキング レコードを修正することです。このフェーズの一時停止時間は通常、初期マーキング フェーズよりもわずかに長くなりますが、同時マーキング時間よりもはるかに短くなります。

「コレクター スレッドは、プロセス全体で最も時間のかかる同時マーキングおよび同時クリア プロセス中にユーザー スレッドと連携できるため、CMS コレクターのメモリ回復プロセスは通常、ユーザー スレッドと同時に実行されます。」

長所と短所:

  • 同時収集、低停止
  • 大量のスペースフラグメントが生成され、同時フェーズによりスループットが低下する
  • CMS初期マーク
  • 同時マーク(CMS同時マーク)
  • CMSコメント
  • 同時スイープ(CMS同時スイープ)

「G1 コレクター」(Java ヒープ全体: 若い世代と古い世代を含む)

G1 の特徴は、同時実行性と並列性、空間統合 (全体としてはマーク アンド スイープ方式に似ており、メモリの断片化は発生しません)、世代別コレクション、および「予測可能な一時停止」(ユーザーが M ミリ秒の時間セグメントを明示的に指定でき、ガベージ コレクションに費やされる時間が N ミリ秒を超えてはならないという点で CMS よりも高度です) です。

G1 コレクターは、Java ヒープを同じサイズの複数のリージョン (独立した領域) に分割します。新しい世代と古い世代はどちらもいくつかの領域のコレクションであり、G1 のコレクション範囲はこれらの領域です。

ワークフロー全体: 初期マーキング、同時マーキング、最終マーキング、スクリーニング、リサイクル。初期マーキング フェーズでは、GC ルートに直接関連付けることができるオブジェクトのみをマークし、TAMS (マーク開始時の次のトップ) の値を変更します。これにより、次のフェーズのユーザー プログラムが同時に実行されるときに、適切な使用可能な領域にオブジェクトを作成できます。このフェーズではスレッドを一時停止する必要があります。同時マーキング フェーズでは、GC ルートからの到達可能性分析を実行して、残存するオブジェクトを見つけます。このフェーズはユーザー スレッドと同時に実行されます。最終マーキング フェーズでは、同時マーキング フェーズでのユーザー プログラムの同時実行によりマークが変更されたレコードを修正します。これらのレコードは、Remembered Set ログに保存されます。最後のマーキング フェーズでは、ログ内のレコードが記憶セットにマージされます。このフェーズは並列で実行され、ユーザー スレッドを一時停止する必要があります。最後に、スクリーニング段階では、まず各地域のリサイクル価値とコストを分類し、ユーザーが想定するGC停止時間に基づいてリサイクル計画を策定します。

メモリ割り当て戦略

  • オブジェクトは最初にEdenに割り当てられます

ほとんどの場合、オブジェクトは新しい世代の Eden に割り当てられます。 Eden スペースが不足すると、マイナー GC が開始されます。

  • 大きなオブジェクトは直接古い世代に送られます

大きなオブジェクトとは、連続したメモリ領域を必要とするオブジェクトを指します。最も一般的な大きなオブジェクトは、非常に長い文字列と配列です。

大きなオブジェクトが頻繁に出現すると、大きなオブジェクトに割り当てるために十分な連続領域を確保するために、ガベージ コレクションが早期にトリガーされます。

-XX:PretenureSizeThreshold、この値より大きいオブジェクトは、Eden と Survivor 間で大量のメモリがコピーされるのを避けるために、古い世代に直接割り当てられます。

  • 長寿命オブジェクトは古い世代に入る

オブジェクトに対して経過時間カウンタが定義されます。オブジェクトが Eden で生成され、Minor GC を生き残った場合、Survivor に移動され、その年齢は 1 年増加します。一定の年齢に達すると、古い世代に移動されます。

-XX:MaxTenuringThreshold は、年齢しきい値を定義するために使用されます。

  • 動的オブジェクト年齢判定

仮想マシンでは、オブジェクトを古い世代に昇格させる前に、必ずしもオブジェクトの年齢が MaxTenuringThreshold に達する必要はありません。 Survivor 内の同じ年齢のすべてのオブジェクトのサイズの合計が Survivor スペースの半分より大きい場合、その年齢以上のオブジェクトは、MaxTenuringThreshold で必要な年齢まで待たずに、直接古い世代に入ることができます。

  • スペース割り当て保証

マイナー GC が発生する前に、仮想マシンはまず、古い世代で使用可能な連続領域の最大サイズが、新しい世代のすべてのオブジェクトの合計領域よりも大きいかどうかを確認します。条件が満たされた場合、マイナー GC が安全であることが確認できます。

そうでない場合、仮想マシンは HandlePromotionFailure の値が失敗の保証を許可するかどうかを確認します。そうなる場合、古い世代で使用可能な連続領域の最大値が、古い世代に昇格されたオブジェクトの平均サイズより大きいかどうかを引き続き確認します。大きい場合は、マイナー GC を実行しようとします。より小さい場合、または HandlePromotionFailure の値がリスクを許容しない場合は、Full GC が実行されます。

巨人の肩

https://github.com/CyC2018/CS-Notes

この記事はWeChatの公開アカウント「Multi-Select Parameters」から転載したものです。以下のQRコードからフォローできます。この記事を転載する場合は、Multi-Select Parameters の公開アカウントにご連絡ください。

<<:  この記事ではPythonの分散プロセスインターフェースを紹介します

>>:  運用者の実践から、「インテリジェントマルチクラウド」がクラウド戦略成功の鍵となった理由

推薦する

ブランドは中国のバレンタインデー期間中のマーケティング機会をどのように活用するのでしょうか?来て学んでください。

現実でも文学作品でも、私たちはみな人生の中で完璧な愛に出会うことを切望しています。中国のバレンタイン...

Google の利用可能な Hosts ファイル

Google は引き続きブロックされており、多くの人から Google にアクセスする方法を尋ねるメ...

SEO業界の倫理規定についても

SEO 業界は規制される必要がありますか?はい、しかし規範は道徳から来るものではありません。倫理を利...

ドメイン名とSEOの関係

良いドメイン名はウェブサイトにとって非常に重要な役割を果たしますが、 SEOの観点からのみ見ると、ド...

SAP は顧客のクラウドファーストのビジネス戦略の構築を支援します

最近、SAP は、すべての顧客がスムーズにクラウドに移行し、クラウドによってもたらされるイノベーショ...

コンテナは運用と保守に不可欠な機能となっています。それらがどのようにして生まれたのか知っていますか?

運用・保守業界は2019年に大きな変化を遂げました。多くの新技術の登場に加え、もともと概念段階にあっ...

リンクとドメインに関する誤解を分析する

最近、いくつかの SEO フォーラムを閲覧していたのですが、投稿を読んでいると、一部の SEO 担当...

#BlackWeek5# 予算vm-20USD/D525/4GB RAM/500GB HDD/5IP/IPMI

budgetvm.com では、ブラック フライデー スペシャルで安価なサーバーをご提供しています。...

Kubernetesの未来はFacebookの先例に従うだろう

[編集者注]現在、Kubernetes は最大で約 5,000 個のノードを管理しています。これは、...

Eコマースゲームの設計と計画手法(パート2)

コンテンツベースの電子商取引の時代が静かに到来し、電子商取引ゲームが徐々に私たちの視界に入ってきまし...

unesty: ドイツの VPS、1Gbps 帯域幅、無制限のトラフィック、月額 2.49 ユーロ、1G メモリ/1 コア/25g SSD/4 コア

unesty は 2009 年に設立されたドイツの企業です。仮想ホスティング、VPS、クラウド サー...

ローカルウェブサイト間の競争と反競争的戦術

競争相手間の話題については話したくなかった。双方が文章や口頭で互いを批判し合っており、傍観者の方がは...

3年連続でガートナーマジッククアドラントにランクインしたEnlightenment Guoxinは、業界をリードする国内ソフトウェアを開発しました。

最近、著名な調査・コンサルティング組織であるガートナーが 2018 UEM マジック クアドラント「...

Dockerの軽量仮想化、イメージ、コンテナの詳細な説明

仮想化技術とは何ですか?サーバーの場合、リソースはほとんどの場合アイドル状態であり、十分に活用されて...