JVMメモリモデルとガベージコレクションアルゴリズムの基本的な理解

 

次の図に示すように、Java言語では、共有メモリモデルを使用して、複数のスレッド間で情報交換とデータ同期を実現します。

 

 

プログラムカウンタ:バイトコードの行番号インジケータ。

効果:

  1. バイトコードインタープリターは、プログラムカウンターを変更することで命令を順次読み取り、順次実行、選択、ループ、例外処理などのコードフロー制御を実現します。
  2. マルチスレッドの場合、プログラムカウンタを使用して現在のスレッド実行の位置が記録されるため、スレッドが元に戻されたときに、スレッドが最後に実行された場所を知ることができます。

プログラムカウンタは、OutOfMemoryErrorが発生しない唯一のメモリ領域であり、そのライフサイクルはスレッドの作成時に作成され、スレッドの終了時に終了します。

 

仮想マシンスタック

プライベート、ライフサイクル=スレッド; Java実行メモリモデル、各メソッド呼び出しのデータはスタックを介して渡されます

構成:スタックフレームで構成され、各スタックフレームには、ローカル変数テーブル、オペランドスタック、動的リンク、メソッドの開始および終了情報があります。

ローカル変数テーブル:さまざまなデータ型とオブジェクト参照を格納します

 

ネイティブメソッドスタック

仮想マシンスタックと同様に、違いは次のとおりです。仮想マシンスタックは仮想マシンの実行メソッドを提供し、ローカルメソッドスタックは仮想マシンが使用するネイティブメソッドを提供します。

 

ヒープ

仮想マシンの起動時に作成される最大のメモリ

目的:オブジェクトインスタンス、配列を格納します

ガベージコレクションのメインエリア

 

メソッドエリア、ストレージ

1.クラス情報(名前、修飾子など)、

2.クラスの静的定数、

3.クラスの最終型として定義されている定数。

4.クラスのフィールド情報、

5.クラスのメソッド情報

一定のプールに分割

文字列、最終変数

クラス名とインターフェース名、フィールド名、記述子、メソッド名

静的変数

親クラス静的メンバー変数、サブクラス静的メンバー変数、親クラス構築メソッド、サブクラス構築メソッド

 

メタスペース:クラス情報;コンパイルされたコード

 

メインメモリとワーキングメモリ

JVMは、すべての変数がメインメモリに格納されることを規定しています。各スレッドには独自の作業メモリー(作業メモリー)もあります。スレッドの作業メモリーは、スレッドが使用する変数のメインメモリーのコピーを保存します。変数のすべての操作(読み取り、割り当てなど)を実行する必要があります。メインメモリ内の変数は、作業メモリで直接読み書きできません(揮発性変数には作業メモリのコピーがありますが、操作の順序が特別であるため、直接読み取りおよび書き込みアクセスのように見えますメインメモリ内)。異なるスレッドは、互いの作業メモリー内の変数に直接アクセスすることはできません。スレッド間の値の転送は、メインメモリーを介して行う必要があります。

したがって、2つのスレッド間の可視性を実現する方法については、揮発性の使用に関する記事を参照してください:https//blog.csdn.net/Goligory/article/details/89648177

 

メモリオーバーフローの理由:

ゴミが多すぎるjvmは時間内にリサイクルされませんでした

1.静的を使用する参照変数が多すぎます

2.多数の再帰と無限再帰(再帰内の新しいオブジェクト)

3.ループの数が多い(ループ内の新しいオブジェクト)/無限ループ内のエンティティが多すぎる

4.一度に100,000を超えるすべてのレコードをチェックするデータベースクエリは、オーバーフローを引き起こす可能性があります

5.文字列が使用する+操作が多すぎませんか

起動パラメータのメモリ値の設定が小さすぎます

 

スタックオーバーフローの理由:

1.再帰的に呼び出すかどうか、メソッドを再帰的に呼び出す

2.多数のループ/無限ループ

3.グローバル変数が多すぎませんか?

4.配列、リスト、マップが大きすぎるかどうか

ヒープオーバーフロー:再帰的な新しいオブジェクト

 

メモリーリーク

メモリが適用された後、適用されたメモリスペースを解放することはできず、メモリリークと蓄積の結果は非常に深刻です。

1.頻繁なメモリリーク:複数回の実行

2.時折のメモリリーク:

3. 1回限りのメモリリーク:コンストラクタで割り当てられたメモリが解放されないなど、1回だけ実行します

4.暗黙のメモリリーク:プログラムはメモリの割り当てを継続し、終了後にメモリを解放します。厳密に言えば、リークはありませんが、時間内に解放されないと、すべてのメモリが使い果たされる可能性があります。

漏れの原因

寿命の短いオブジェクトを保持している寿命の長いオブジェクトは、参照の保持につながり、リサイクルできず、メモリリークが発生します

1.静的コレクションクラスはメモリリークを引き起こします:HashMap、vectorなど

2.リスナー。オブジェクトが解放されても削除されません。

3.さまざまなリンクが閉じられていません

4.シングルトンモードは外部オブジェクト参照を保持します

 

 

============ GCガベージコレクション=================================== ================================================== ================================================== ================================================== ================================================== === ===============================

ガベージコレクションに精通している必要があります。ガベージコレクションがどのように機能するのか、なぜ機能するのか、そしてどのようなメリットがあるのか​​を知る必要があります。

ヒープはGCの主要な領域です

jdk1.8以降、永続世代はダイレクトメモリを使用するメタスペースに変更されます

 

JVMは、どのオブジェクトをリサイクルする必要があるかをどのように決定しますか?

ふたつのやり方

1.参照カウント方法:オブジェクトにカウンターを追加し、-1ではなく+1を使用しますが、オブジェクト間の循環参照の問題を解決することはできません。Javaは役に立ちません。

2.到達可能性分析アルゴリズム:

参照チェーンGCルートと呼ばれるいくつかのオブジェクトを開始点として使用し、これらのノードから開始して下方向に検索すると、通過するパスは参照チェーンと呼ばれます。オブジェクトが参照チェーンなしでGCルートに接続されている場合(つまり、GCルートからノードに到達できません)、オブジェクトが使用できないことを証明します

GCルートとして使用できるオブジェクトは次のとおりです。

  • 仮想マシンスタックで参照されるオブジェクト
  • メソッド領域クラスの静的プロパティによって参照されるオブジェクト
  • メソッド領域の定数参照オブジェクト

リサイクルされるオブジェクトを知っていますか、いつリサイクルされますか?リサイクルする方法は?


いつリサイクルされますか?

CPUがアイドル状態のときに自動的にリサイクル

ヒープメモリがいっぱいになった後

System.gc()を積極的に呼び出す

 

3つの主要なリサイクルアルゴリズム

1.标记/清除算法【最基础】
2.复制算法
3.标记/整理算法
jvm采用`分代收集算法`对不同区域采用不同的回收算法。

 

  • マークスイープアルゴリズム:最初にマークを付けてからクリアし、リサイクルが必要なすべてのオブジェクトにマークを付けてから、マークされたオブジェクトを均一にリサイクルします。単純ですが非効率的なスペースの問題です。マークが付けられた後、多数の不連続なメモリフラグメントが生成されます。クリア、プログラムの実行中大きなオブジェクトを割り当てる必要がある場合、十分な連続メモリが見つからず、スペースの浪費が発生します
  • マークデフラグアルゴリズム:マーククリアアルゴリズムと同様に、マーククリアは残りのオブジェクトに対して動作せず、メモリの断片化を引き起こします。マークデフラグがクリアされた後、残りのオブジェクトはメモリの断片化なしで並べ替えられます。

 

新世代:レプリケーションアルゴリズム

エデン、サバイバーから、サバイバーへ

Javaオブジェクトは一般的に新世代で生まれます。これはGCの頻繁な領域でもあります。JVM仮想マシンを深く理解すると、オブジェクトの生存率の98%が非常に低く、レプリケーションアルゴリズムに適していると言われています。

マーク/スイープアルゴリズムの効率とメモリの断片化の問題を最適化し、JVMは5:5にメモリを割り当てません[生存率が低いため、このような大きな領域をコピーして予約する必要はありません。スペースの浪費が発生するため、1:1 [元の領域:予約済みスペース]を押す必要はありません。メモリ領域を分割しますが、メモリをエデンスペースとサバイバーからサバイバー[予約済みスペース]に分割します。 3つのデフォルトの比率は8:1:1です

ライフサイクルの短いオブジェクトをできるだけ早く収集することが目標です。一般的に、エデンエリアで新しく生成されたオブジェクトは、最初に新世代に配置されます。ガベージコレクションでは、最初にエデンエリアのサバイバーオブジェクトがサバイバー0エリアにコピーされ、次にエデンエリアがクリアされます。サバイバー0エリアがいっぱいになると、エデンエリアとサバイバー0エリアのサバイバーオブジェクトがサバイバー1エリアにコピーされます。 、次にedenエリアとsurvivor0エリアがクリアされ、survivor0が交換されます。エリアとsurvivor1エリアの役割、次のガベージコレクションはedenエリアとsurvivor1エリアをスキャンします。

サバイバー1エリアがエデンエリアとサバイバー0エリアにサバイバーオブジェクトを格納するのに十分でない場合、サバイバーオブジェクトは古い世代に直接格納されます。古い世代もいっぱいになると、FullGCがトリガーされます。つまり、新しい世代と古い世代の両方がリサイクルされます。

新世代で発生するGCはMinorGCとも呼ばれます。MinorGCはより頻繁に発生し、エデン領域がいっぱいになったときに必ずしもトリガーされるとは限りません。

 

老後:マーククリア;マーク整理

  • ヒープサイズ:若い世代+古い世代。ヒープサイズは、-xms(ヒープ初期容量)、-xmx(ヒープ最大容量)に従って指定できます。
  • 新世代のデフォルトのエデン:from:to = 8:1:1
  • Jvmは、一度にEdenとサバイバーエリアの1つでのみオブジェクトを提供します。いつでも、アイドル状態のサバイバーが常に存在します。
  • 新世代で使用可能な実際のメモリスペースは、新世代スペースの9/10です。

旧世代はライフサイクルの長いオブジェクトを格納し、若い世代でn回のガベージコレクションを行った後も存続しているオブジェクトは旧世代に配置されます。

 

永久世代

主に、Javaクラスやメソッドなどの静的ファイルを保存します。永続的な生成は、ガベージコレクションに大きな影響を与えません。ただし、リフレクション、動的プロキシ、CGLibなどは、クラスファイルを動的に生成する場合があります。このとき、ストレージ用に比較的大きな永続的な生成スペースを設定する必要があります。

大きな物や長寿命の物が老後を迎える

 

注:jdk1.8は永続的な世代を破棄し、同様のメタスペーステクノロジーを提供します

永続的な世代に移行する理由は次のとおりです。 

(1)文字列は永続世代に存在するため、パフォーマンスの問題やメモリオーバーフローが発生しやすくなります。 

(2)クラスとメソッドの情報のサイズを判別するのが難しいため、永続世代のサイズを指定するのが困難です。小さすぎると永続世代がオーバーフローし、大きすぎると永続世代がオーバーフローします。古い世代が簡単にオーバーフローします。 

(3)永久生成は、GCに不必要な複雑さをもたらし、回復効率が低い

 

JVMパラメータ

最小および最大ヒープメモリを指定します

-Xms2G -Xmx5G

 

新世代の新しいオブジェクトを予約します。フルGCのコストはマイナーGCのコストよりもはるかに高いため、できるだけ新しい世代のオブジェクトを割り当てるのが賢明です。実際のプロジェクトでは、新しいオブジェクトのスペース割り当てかどうかを分析します。 GCログによると、世代は合理的で適切です。「-Xmn」コマンドを使用して若い世代のサイズを調整し、新しいオブジェクトが古い世代に直接入る状況を最小限に抑えます。

 

明示的な新世代メモリ、指定する2つの方法

1.-XX:newSize = 256m

-XX:MaxNewSize = 1024m

2.-Xmn256m

 

指定したメタスペースのサイズを表示します

ダイレクトメモリを使用すると、仮想マシンのシステムメモリが不足する可能性があるため、Jdk8ではメタベースサイズを指定する必要があります

 

ガベージコレクター

1.シリアルガベージコレクター

2.並列ガベージコレクター

3.CMSガベージコレクター

4.G1ガベージコレクター

ヒープパラメータ

 

コレクターパラメーター

 

一般的なコマンド

 

GCチューニングの原則

ほとんどのJavaアプリケーションはサーバー上でGCの最適化を必要としません。GCの問題を引き起こすほとんどのJavaアプリケーションは、パラメーター設定エラーが原因ではなく、コードの問題が原因です。アプリケーションがオンラインになる前に、マシンのJVMパラメーターを最適に設定することを検討してください。適切);作成されるオブジェクトの数を減らす;グローバル変数と大きなオブジェクト(連続メモリスペースを占有する)の使用を減らす; GC最適化は最後の手段です;実際の使用では、GC条件の分析とコードの最適化はGCパラメータの最適化よりも優れていますはるかに

 

チューニング戦略

1.新しいオブジェクトは新しい世代で予約され、新しいオブジェクトが古い世代に直接入る状況を最小限に抑えるために、新しい世代のサイズは-Xmnを介して調整されます

2.大きな物が老後を迎える

3.古い年齢のオブジェクトの年齢を合理的に設定します-XX:MaxTenuringThreshold

4.安定したヒープサイズを設定します

5.注:次のステートメントを満たすためにGCの最適化は必要ありません

マイナーGCの実行時間は50ミリ秒未満、マイナーGCの実行頻度は約10秒に1回、フルGCの実行時間は1秒未満、フルGCの実行頻度はそれほど頻繁ではなく、10分に1回以上

 

 

 

 

参照:https://www.cnblogs.com/shenjianjun/p/9512949.html

           GC https://www.cnblogs.com/ITPower/p/7929010.html

この引用は非常に包括的な推奨事項です:https//www.jianshu.com/p/76959115d486

おすすめ

転載: blog.csdn.net/Goligory/article/details/104429787