ホームページ  >  記事  >  Java  >  JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)

不言
不言転載
2018-10-16 17:02:123625ブラウズ

この記事では、JVM のメモリ モデルとランタイム データ領域について詳しく説明します (写真とテキスト)。必要な方は参考にしていただければ幸いです。

1. Java メモリ モデル

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)

Java のメモリ モデル定義の目的は次のとおりです。さまざまなハードウェアおよびオペレーティング システムのメモリ アクセス間の違いをマスクします。

Java メモリ モデルでは、すべての変数がメイン メモリに格納されることが規定されており、各スレッドには独自の作業メモリがあり、変数のコピーがメイン メモリに保存されます。

スレッドは作業メモリ内の変数に対してのみ操作でき、メイン メモリ内の変数を直接読み書きすることはできません。

異なるスレッド間の変数アクセスは、メイン メモリを通じて完了する必要があります。

1. Java メモリ モデルと Java ランタイム データ領域の関係: メイン メモリは Java ヒープに対応し、ワーキング メモリは Java スタックに対応します。

2. volatile キーワードにより、変数の更新が各作業メモリ内でリアルタイムに表示されます。 DCLのシングルトンモードで使用します

2. Java実行時データ領域/メモリ領域

jvmの実行時データ領域が改良されているため、 JDK のバージョンが異なると違いが生じます。

1. jdk1.7 より前の jvm メモリ領域には、永続的な世代の

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)1 があります。 .java ファイルは .class ファイルにコンパイルされるため、カウンターの役割は、現在のスレッドによって実行されるバイトコードの行番号インジケーターとして機能します。バイトコード インタプリタが動作するとき、この計算器の値を変更することによって、実行する次のバイトコード命令を選択します。各スレッドには独立したプログラム カウンタがあります。

2. ローカル メソッド スタックは、ローカル ネイティブ メソッドを実行するスタックであり、仮想マシンによって実装されます。

3. Java 仮想マシン スタックは、スレッドが Java メソッド (メソッド) を実行するときのメモリ モデルを記述します。各メソッドはスタック フレームに対応し、スタック フレーム内のローカル変数テーブルにはメソッド内の基本データ型変数とオブジェクト参照変数が格納されます。

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)#上図に示すように、ローカル変数テーブルには、メソッド内で宣言された 8 つの基本型変数とオブジェクト参照変数が保存されます。各スタック フレームには、String 型を参照するランタイム定数プールへの参照もあります。 以下は、String オブジェクトによって生成される典型的なインタビューの質問です。

4. Java ヒープは JVM 内の最大のメモリ部分であり、すべてのスレッドによって共有されます。ほとんどすべてのオブジェクト インスタンスがここに割り当てられるため、したがって、Java ヒープは JVM ガベージ コレクションのメイン領域でもあります。

Java ヒープは若い世代と古い世代に分かれており、若い世代はさらに Eden 空間、From Survivor 空間、To Survivor 空間に分けることができます。

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)new キーワードを使用してオブジェクトを割り当てると、オブジェクトは Java ヒープに生成されます。

オブジェクトが生成されたときの状況を分析してみましょう。

Eden が最大であるため、新しく生成されたオブジェクトは Eden 空間に割り当てられ、Eden 空間がほぼいっぱいになるとマイナー GC が実行され、残ったオブジェクトが Eden 空間にコピーされます。 From Survivor スペース。現時点では、Eden 空間は外部にヒープ メモリを提供し続けます。
  1. 後で生成されるオブジェクトは引き続き Eden スペースに配置されます。Eden スペースが再びいっぱいになると、この時点で Eden スペースと From Survivor スペースが実行されます。同時にマイナー GC を実行すると、生き残ったオブジェクトが To Survivor スペースに配置されます。現時点では、Eden 空間は外部にヒープ メモリを提供し続けます。
  2. 次の状況は 2 と一致します。 Eden スペースがほぼいっぱいになると、Eden スペースと To Survivor スペースでマイナー GC が実行され、残ったオブジェクトが From Survivor スペースに配置されます。
  3. 次の状況は 3 と一致します。 Eden スペースが速いか遅い場合、Eden スペースと From Survivor スペースはマイナー GC を実行し、その後、生き残ったオブジェクトが To Survivor スペースに配置されます。
  4. つまり、2 つの Survivor のうち 1 つはオブジェクト ストレージを提供するために使用されます。
  5. Eden スペースと特定の Survivor スペースが GC され、他の Survivor スペースが GC を生き残ったオブジェクトを保持できない場合、またはマイナー GC が約 15 回連続して実行された場合、これらの生き残ったオブジェクトは旧世代のスペースに置きます。

    古い世代のスペースもいっぱいになると、古い世代のスペースをリサイクルするためにメジャー GC が実行されます。 (
  6. フル GC
  7. とも呼ばれます。フル GC は大量のメモリを消費するため、避ける必要があります)

若い世代はコピー アルゴリズムを使用します。マイナー GC が Eden エリアと Survivor エリアに残っているオブジェクトを別の Survivor エリアにコピーするたびにです。古い世代では、マーク補完アルゴリズムが使用されます。メジャー GC が実行されるたびに、残っているオブジェクトがメモリ空間の一端に移動され、その後、端の境界の外側にあるメモリが直接クリーンアップされます。

配列や非常に長い文字列などの大きなオブジェクトは、古い世代スペースに直接入ります。

5. メソッド領域は、クラス情報、最終定数、静的変数、および JVM によってロードされるその他のデータを格納するために使用されます。メソッド領域のデータはプログラム全体で一意です。メソッド領域には、主にコンパイル中に生成されたリテラルとシンボル参照 (クラスのロード後に配置される) を格納する実行時定数プールも含まれています。 String オブジェクトのリテラルは、実行時定数プールに入れられます。

メソッド領域のガベージ コレクションには、主に定数のリサイクルと型のアンロードが含まれます。

#2、jdk1.8 以降の JVM メモリ領域、メタスペースは永続世代を置き換えます

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)

# #メタスペースと永続世代のプロパティは同じであり、どちらも JVM メソッド領域の実装であり、同じ機能を持ちます。ただし、メタスペースと永続生成の最大の違いは、メタスペースは仮想マシンの JVM メモリ内になく、ローカル メモリを使用することです。

なぜメタスペースを使用して永続世代を置き換えるのでしょうか?

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

  2. クラスやメソッドの情報はサイズを決めるのが難しいため、永続世代のサイズを指定するのが難しく、小さすぎると永続世代が発生しやすくなります。それが大きすぎると、古い世代が簡単にオーバーフローしてしまいます。

  3. 永続的な生成は GC に不必要な複雑さをもたらし、リサイクル効率が低くなります。

ダイレクト メモリ

JDK1.4 でチャネル チャネルとバッファ バッファに基づく IO が導入された後に追加された NIO (ネイティブ関数を直接使用) オフヒープの割り当てメモリにより IO パフォーマンスが大幅に向上し、元の BIO による Java ヒープとナイーブ ヒープの間でのデータのコピーが回避されます。

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)

#3. String 生成時のメモリ割り当て

参考記事:

string の詳細説明Java

の定数プール。

4. オブジェクト生成時のメモリ状況

オブジェクトまたは基本的なデータ型変数を生成するための一般的なメモリ モデルを分析してみましょう。これにより、JVM についてより深く理解できるようになります。

int i =3; の場合、メソッドはスタック フレームに対応し、メソッド内の基本データ型変数はスタック フレームに直接割り当てられます。静的データ型または最終的な基本データ型の場合は、文字列と同様にランタイム定数プールに保存されます。

Object o1 = new Object();、オブジェクト参照 (Object o1) はスタック フレームに保存されますが、オブジェクト データ (new Object()) は Java ヒープに保存され、オブジェクト タイプdata (クラスなどの情報) メソッド領域に格納されます。

String s1 = new String("abcd");、newで宣言したオブジェクトを使用し、オブジェクト参照(String s1)はスタックフレームに格納され、オブジェクトデータ(new String("abcd") )) は Java に格納されます。ヒープでは、文字列値 (「abcd」) がランタイム定数プールに格納されます。

String s2 = "abc"、オブジェクト参照 (String s2) はスタック フレームに格納され、文字列値 ("abc") はランタイム定数プールに格納されます。

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)Java スタック、Java ヒープ、メソッド領域の関係は、おおよそ上記の分析に示されているとおりです。

3. 各種例外解析

1. Java ヒープメモリオーバーフローエラー OutOfMemoryError

Java ヒープが割り当てられている場合オブジェクトが多すぎるため、GC 後もメモリ領域がまだ十分ではありません。次のテストは、オブジェクトを周期的に生成してメモリ領域を消費することによって実行されます。

関連命令:

VM 引数: -Xms20m -Xmx40m

。JVM によって割り当てられるヒープ メモリの最小値が 20MB、最大値が 40MB であることを示します。 <pre class="brush:php;toolbar:false"> public static void main(String[] args) {    while (true) {      List&lt;object&gt; list = new ArrayList(10);      list.add(new Object());    }  }&lt;/object&gt;</pre>

2. Java スタック スタック オーバーフロー エラー StackoverflowError

Java スタックのスタックの深さが JVM で許可されている深さより大きい場合、このエラーがスローされます。 。以下は、無限再帰呼び出しによるスタック テストです。

関連命令:

VM 引数: -Xss128k

、JVM によって割り当てられたスタック容量が 128KB であることを示します。 <pre class="brush:php;toolbar:false">public class StackOOM {          private int length = 1;          public void stackLeak() {         length++;         stackLeak();     }          public static void main(String[] args) {         StackOOM stackOOM = new StackOOM();         stackOOM.stackLeak();     } }</pre>

JVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)

以上がJVMメモリモデルとランタイムデータ領域の詳細説明(画像とテキスト)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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