ホームページ  >  記事  >  Java  >  Java メモリ分布の概要を共有する

Java メモリ分布の概要を共有する

Y2J
Y2Jオリジナル
2017-04-28 10:09:461458ブラウズ

この記事では主に、Java プログラム実行時のメモリ配分の詳細な説明を紹介します。必要な方は参考にしてください。

Java メモリ配分: Java プログラムの実行中に、Java 仮想マシンはメモリを分割します。メモリは、メソッド領域、仮想マシン スタック、ローカル メソッド スタック、ヒープ、プログラム カウンターなど、いくつかの異なるデータ領域に管理されます。

1. プログラムカウンター

プログラムカウンターは、現在のスレッドによって実行されるバイトコードの行番号インジケーターと見なすことができます。仮想マシンの概念モデルでは、バイトコード インタープリターは、このカウンターの値を変更して、実行する必要があるバイトコード命令を選択することによって機能します。

分岐、ループ、ジャンプ、例外処理、スレッド回復などの基本的な機能はすべて、このカウンターに依存して完了します。

スレッド切り替え後に正しい実行位置に戻るには、各スレッドが独立したプログラムカウンターを持つ必要があります。各スレッド間のカウンターは相互に影響せず、独立して保存されるため、このタイプのメモリ領域は「スレッドプライベート」となります。 " メモリ。

スレッドが Java メソッドを実行している場合、このカウンタは実行されている仮想マシンのバイトコード命令のアドレスを記録します。スレッドがネイティブ メソッドを実行している場合、カウンタ値は空であり、このメモリ領域は Java の唯一の領域です。仮想マシンの仕様では、OutOfMemoryError 状況に対応する領域は指定されていません。

2. Java 仮想マシン スタック

プログラム カウンターと同様に、Java 仮想マシン スタックもスレッドに対してプライベートであり、そのライフサイクルはスレッドと同じです。仮想マシン スタックは、Java メソッド実行のメモリ モデルを記述します。各メソッドが実行されると、ローカル変数テーブル、オペランド スタック、ダイナミック リンク、メソッド出口などの情報を格納するスタック フレームが作成されます。

各メソッドの呼び出しから実行完了までは、スタック フレームが仮想マシン スタックにプッシュされ、その後スタックからポップアウトされるプロセスに対応します。

ローカル変数テーブルには、コンパイル時に既知のさまざまな基本データ型、オブジェクト参照 (オブジェクトと同等ではなく、オブジェクトへの参照)、および returnAddress 型が格納されます。スレッドによって要求されたスタックの深さが仮想マシンで許可されている深さより大きい場合、StackOverflowError 例外がスローされ、十分なメモリを適用できない場合は OutOfMemory 例外がスローされます。

3. ローカル メソッド スタック

ローカル メソッド スタックと仮想マシン スタックの違いは、仮想マシン スタックは仮想マシンによって実行される Java (バイトコード) を提供するのに対し、ローカル メソッド スタックは仮想マシンのネイティブ メソッド サービス。

4.Java ヒープ

Java ヒープは、すべてのスレッドによって共有されるメモリ領域であり、仮想マシンの起動時に作成されます。このメモリ領域の唯一の目的は、オブジェクト インスタンスを保存することです。Java ヒープは、ガベージ コレクターによって管理されるメイン領域です

メソッド領域は、Java ヒープと同様に、ガベージ コレクターによって共有されるメモリ領域です。各スレッドに存在し、クラス情報、定数、静的変数、仮想マシンにロードされるジャストインタイム コンパイラによってコンパイルされたコードなどのデータを保存するために使用されます。

6. ランタイム定数プール

ランタイム定数プールはメソッド領域の一部です。クラス ファイルには、クラスのバージョン、フィールド、メソッド、インターフェイスなどの記述情報に加えて、コンパイル中に生成されるさまざまなリテラルやシンボル参照を格納するために使用される定数プールもあります。クラスにロードされ、メソッド領域の実行時定数プールに格納されます。

インターネット上の定数プールの多くの説明では、例として文字列が使用されています。

たとえば、

String s1 = "Hello";
String s2 = "Hello";
String s3 = "Hel" + "lo";
String s4 = "Hel" + new String("lo");
String s5 = new String("Hello");
String s6 = s5.intern();
String s7 = "H";
String s8 = "ello";
String s9 = s7 + s8;
 
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // true
System.out.println(s1 == s4); // false
System.out.println(s1 == s9); // false
System.out.println(s4 == s5); // false
System.out.println(s1 == s6); // true

s1==s2 は true であり、同じ定数プールのメモリ アドレスを指しており、理解しやすいです。

s1==s3 は true: s3 の場合、すべての連結はリテラルであるため、コンパイラーは最適化します。これは実際には s3="Hello" を意味します

s1==s4 は false: new String( "lo") がそうでないためリテラルですが変数です。この場合、変数は変更される可能性があるため、コンパイラーは最適化しません。

s1==s9 は false: 上記と同じ。

s4==s5: 2 つの異なるオブジェクトの参照は当然異なります。

s1==s6:

String.intern()

メソッドの意味: 定数プールにこの String オブジェクトと等しい文字列が既に含まれている場合 (オブジェクトは

equals(Object) メソッドによって決定されます)、リターンプールへの文字列。それ以外の場合、この String オブジェクトはプールに追加され、この String オブジェクトへの参照が返されます。 したがって、任意の 2 つの文字列 s および t について、s.intern() == t.intern() は、s.equals(t) が true の場合にのみ true になります。

以上がJava メモリ分布の概要を共有するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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