ホームページ  >  記事  >  Java  >  Javaのメモリモデルを画像と文章で詳しく解説

Javaのメモリモデルを画像と文章で詳しく解説

尚
転載
2019-11-30 16:27:262322ブラウズ

Javaのメモリモデルを画像と文章で詳しく解説

#1. 概要

マルチタスクと高い同時実行性は、能力を測定するための重要な指標の 1 つです。コンピューターのプロセッサーの 1 つ。一般に、サーバーのパフォーマンスを測定するには、1 秒あたりのトランザクション数 (TPS) という指標がより具体的です。これはサーバーが 1 秒間に応答できるリクエストの平均数を表し、TPS 値はプログラムの同時実行機能に関連しています。は非常に密接な関係にあります。 Java メモリ モデルとスレッドについて説明する前に、ハードウェアの効率と一貫性について簡単に紹介します。 (推奨: java ビデオ チュートリアル )

2. ハードウェアの効率と一貫性

コンピューターのストレージ デバイスによるものメモリとプロセッサの計算能力の間には数桁の差があるため、現代のコンピュータ システムでは、メモリとプロセッサの計算速度に可能な限り近い読み取りおよび書き込み速度のキャッシュ層 (キャッシュ) を、メモリとプロセッサの計算能力との間のバッファとして追加する必要があります。バッファリング: 操作を迅速に実行できるように、操作に必要なデータをキャッシュにコピーします。操作が完了すると、プロセッサが必要としないように、キャッシュからメモリーに同期されます。メモリの読み取りと書き込みが遅いのを待ちます。

キャッシュ ベースのストレージ相互作用は、プロセッサとメモリ間の速度の競合を解決しますが、キャッシュ コヒーレンスという新しい問題が発生します。マルチプロセッサ システムでは、各プロセッサが独自のキャッシュを持ち、同じメイン メモリを共有します。

下の図に示すように: 複数のプロセッサのコンピューティング タスクには同じメイン メモリが必要であり、データの一貫性を確保するためのプロトコルが必要です。このようなプロトコルには MSI、MESI、MOSI、Dragon Protocol などがあります。 Java 仮想マシンのメモリ モデルで定義されたメモリ アクセス操作は、ハードウェア キャッシュ アクセス操作に相当します (Java メモリ モデルについては後ほど紹介します)。

Javaのメモリモデルを画像と文章で詳しく解説

また、プロセッサ内の演算器を最大限に活用するために、プロセッサは入力コードのアウトオブオーダー実行 (Out-Of -順序実行) 最適化では、プロセッサは、結果の正確性を確保するために、計算後に順序どおりに実行されたコードの結果を再編成します。プロセッサのアウトオブオーダー実行の最適化と同様に、Java 仮想マシンのジャストインタイム コンパイラにも同様の命令並べ替え (命令レコーダー) 最適化があります。

3. Java メモリ モデル

Java メモリ モデルの定義は簡単な作業ではありません。このモデルは、Java のメモリ モデルを十分に厳密に定義する必要があります。同時操作によってあいまいさが生じることはありませんが、実行速度を向上させるためにハードウェアのさまざまな機能 (レジスタ、キャッシュなど) を利用するのに十分な空き領域を仮想マシンの実装に確保できるように、同時操作は十分に緩やかでなければなりません。 JDK1.5 のリリース以来、長期間にわたる検証とパッチ適用を経て、Java メモリ モデルは成熟し、改善されました。

3.1 メイン メモリと作業メモリ

Java メモリ モデルの主な目的は、プログラム内の各変数のアクセス ルールを定義することです。仮想マシンのメモリへの変数、およびメモリからの変数の取得などの低レベルの詳細。ここでの変数は、Java プログラミングで言及される変数とは異なります。インスタンス フィールド、静的フィールド、および配列オブジェクトを構成する要素が含まれますが、ローカル変数とメソッド パラメータは含まれません。後者はスレッドに対してプライベートであり、共有されません。 。

Java メモリ モデルでは、すべての変数がメイン メモリに格納されることが規定されています。各スレッドには独自の作業メモリもあります (以前にプロセッサのキャッシュと比較できます)。スレッドの作業メモリのコピースレッドが使用する変数はメインメモリに保存されますが、スレッドによる変数のすべての操作(読み込み、代入)はワーキングメモリ上で行う必要があり、メインメモリ上の変数を直接読み書きすることはできません。

異なるスレッドは、互いのワーキング メモリ内の変数に直接アクセスできません。スレッド間の変数値の転送は、メイン メモリ内で完了する必要があります。スレッド、メイン メモリ、ワーキング メモリ間の対話的な関係が示されています下の図と上の図は非常によく似ています。

Javaのメモリモデルを画像と文章で詳しく解説

ここでいうメインメモリとワーキングメモリは、Javaメモリ領域のJavaヒープ、スタック、メソッド領域と同じレベルのメモリ分割ではありません。

3.2 メモリ間の相互作用

メインメモリとワーキングメモリ間の特定の相互作用プロトコル、つまり変数がメインメモリからワーキングメモリにどのようにコピーされるかについて、ワーキング メモリをメイン メモリに同期する詳細を実装するために、Java メモリ モデルでは、完了する次の 8 つの操作を定義します:

1. ロック: 内の変数に作用します。メインメモリ。変数をスレッド排他状態として識別します。

2. ロック解除: メイン メモリ変数に作用して、ロック状態にある変数を解放します。解放された変数のみが他のスレッドによってロックされます。

3. 読み取り: メイン メモリ変数に作用し、変数値をメイン メモリからスレッドの作業メモリに転送して、後続の読み込みアクションで使用できるようにします。

4. ロード: 作業メモリ内の変数に作用し、読み取り操作によってメイン メモリから取得した変数値を作業メモリ内の変数のコピーに置きます。

5. Use (使用): 作業メモリ内の変数に作用し、作業メモリ内の変数値を実行エンジンに渡します。仮想マシンが、その値を使用する必要があるバイトコード命令に遭遇するたびに、変数がこの操作を実行します。

6. Assign (割り当て): 作業メモリ内の変数に作用します。実行エンジンから受け取った値を作業メモリ内の変数に割り当てます。仮想マシンが変数に値を割り当てるバイトコードを検出するたびに、 , この操作は、指示されたときに実行します。

7. ストア (ストレージ): 作業メモリ内の変数に作用し、後続の書き込み操作のために作業メモリ内の変数の値をメイン メモリに転送します。

8. 書き込み: メイン メモリ内の変数に作用し、ストア操作を作業メモリ内の変数の値からメイン メモリ内の変数に転送します。

変数をメイン メモリからワーキング メモリにコピーする場合は、読み取り操作とロード操作を順番に実行する必要があります。変数をワーキング メモリからメイン メモリに同期させたい場合は、の場合は、読み取り操作とロード操作を順番に実行する必要があり、ストア操作と書き込み操作を実行します。

Java メモリ モデルでは、上記の操作が順番に実行されることのみが必要ですが、これらの操作が連続的に実行されるという保証はありません。つまり、読み取りとロードの間、およびストアと書き込みの間に他の命令を挿入できます。たとえば、メイン メモリ内の変数 a と変数 b にアクセスする場合、可能な順序は、読み取り a、読み取り b、ロード b、ロード a です。 Java メモリ モデルでは、上記の 8 つの基本操作を実行するときに、次のルールを満たす必要があることも規定しています:

1. 読み取り、ロード、ストア、書き込み操作の 1 つを単独で使用することはできません

2. スレッドは最新の代入操作を破棄することはできません。つまり、変数は作業メモリ内で変更された後、メインメモリに同期されなければなりません。

3. スレッドは、理由もなく (割り当て操作が発生していない) 作業メモリからメイン メモリにデータを同期させることはできません。

4. 新しい変数はメイン メモリ内でのみ作成でき、初期化されていない (ロードまたは割り当て) 変数を作業メモリ内で直接使用することはできません。つまり、変数に対して使用および保存操作を実行する前に、割り当ておよびロード操作を最初に実行する必要があります。

5. 同時に変数をロックできるのは 1 つのスレッドだけです。ロックとロック解除はペアで指定する必要があります。

6. 変数に対してロック操作が実行される場合、その作業はメモリ内のこの変数の値は、実行エンジンがこの変数を使用する前に、ロードまたは割り当て操作を再実行して変数値を初期化する必要があります。変数がロックされていない場合は、事前にロック操作を行っている場合、ロックを解除する操作は許可されません。また、他のスレッドによってロックされている変数のロックを解除することもできません。

8. 変数のロック解除操作を実行する前に、変数をメイン メモリに同期する必要があります (ストアおよび書き込み操作を実行)。

3.3 並べ替え

プログラム実行時のパフォーマンスを向上させるために、コンパイラとプロセッサは命令を並べ替えることがよくあります。再順序付けは 3 つのタイプに分類されます:

1. コンパイラに最適化された再順序付け。コンパイラは、シングルスレッド プログラムのセマンティクスを変更せずに、ステートメントの実行順序を再配置できます。

2. 命令レベルの並列並べ替え。最新のプロセッサは、命令レベルの並列処理を使用して、複数の命令をオーバーラップして実行します。データの依存関係がない場合、プロセッサはステートメントが機械語命令に対応する順序を変更できます。

3. メモリ システムの並べ替え。プロセッサはキャッシュと読み取りおよび書き込みバッファを使用するため、ロードおよびストア操作が順序どおりに実行されていないように見える可能性があります。

Java ソース コードから実際に実行される最終的な命令シーケンスまで、次の 3 つの並べ替えが行われます。

メモリの可視性を確保するために、Java コンパイラは命令シーケンス メモリ バリア命令は、特定のタイプのプロセッサの並べ替えを無効にするために適切な場所に挿入されます。 Java メモリ モデルは、メモリ バリアを LoadLoad、LoadStore、StoreLoad、StoreStore の 4 つのタイプに分類します。

Javaのメモリモデルを画像と文章で詳しく解説

Java の詳細については、「

java Basic TutorialJavaのメモリモデルを画像と文章で詳しく解説」列に注目してください。

以上がJavaのメモリモデルを画像と文章で詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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