プロセッサ メモリ モデル
逐次整合性メモリ モデルは理論的な参照モデルであり、通常、JMM およびプロセッサ メモリ モデルを設計する際の参照として使用されます。 JMM およびプロセッサー・メモリー・モデルは、設計時に逐次整合性モデルにある程度の緩和を加えます。これは、プロセッサーと JMM が逐次整合性モデルに従って完全に実装されると、多くのプロセッサーおよびコンパイラーの最適化が禁止され、実行パフォーマンスに悪影響を及ぼすためです。大きな影響を与えるでしょう。
さまざまなタイプの読み取り/書き込み操作の組み合わせの実行順序の緩和に従って、一般的なプロセッサのメモリモデルは次のタイプに分類できます:
プログラム内の書き込み-読み取り操作の順序を緩和し、その結果、合計ストア順序付けメモリ モデル (TSO と呼ばれる)。
前の 1 に基づいて、プログラム内の書き込み-書き込み操作の順序を緩和し続け、その結果、部分ストア順序メモリ モデル (PSO と呼ばれる) が誕生しました。
前の 1 と 2 に基づいて、プログラム内の読み取り-書き込みおよび読み取り-読み取り操作の順序を緩和し続けました。その結果、緩和されたメモリ順序メモリ モデル (RMO と呼ばれる) と PowerPC メモリ モデルが誕生しました。
ここでのプロセッサの読み取り/書き込み操作の緩和は、2 つの操作の間にデータの依存関係がないという前提に基づいていることに注意してください (プロセッサは as-if-serial セマンティクスに準拠する必要があるため、プロセッサは 2 つのメモリ操作を実行しません)相互に依存するものは並べ替えを行います)。
以下の表は、一般的なプロセッサメモリモデルの詳細な特性を示しています:
メモリモデル名
対応するプロセッサ
ストア-ロード並べ替え
ストア-ストア並べ替え
ロード-ロードおよびロード-ストア並べ替え
変更可能 他のプロセッサの書き込みを読み取りますプロセッサをより早く読み込むことができます
TSO
sparc-TSOX64
Y
Y
PSO
sparc-PSO
Y
Y
Y
RMO
ia64
Y
Y
Y
Y
PowerPC
PowerPC
Y
Y
Y
Y
Y
この表では、第 1 章で説明した理由により、すべてのプロセッサー メモリ モデルで書き込み/読み取りの並べ替えが可能であることがわかります。ただし、これらはすべて書き込みバッファを使用するため、書き込み/読み取り操作が発生する可能性があります。並べ替えられます。同時に、これらのプロセッサ メモリ モデルでは、現在のプロセッサへの以前の読み取りまたは書き込みが許可されていることがわかります。その理由は書き込みキャッシュ領域によるものでもあります。書き込みキャッシュ領域は現在のプロセッサにのみ表示されるため、この機能により原因が生じます。現在のプロセッサは、他のプロセッサが自分の書き込みバッファに一時的に保持されている書き込みを最初に認識できるようになります。
上の表のさまざまなプロセッサ メモリ モデルは、上から下に向かって、強力なモデルから弱いモデルへと変化します。プロセッサがパフォーマンスを重視するほど、メモリ モデルは弱くなります。これらのプロセッサは、パフォーマンスを向上させるためにできるだけ多くの最適化を実行できるように、メモリ モデルによる制約を最小限に抑えることを望んでいるからです。
共通プロセッサ メモリ モデルは JMM よりも弱いため、バイトコードを生成する際、Java コンパイラはプロセッサの並べ替えを制限するために、実行命令シーケンスの適切な位置にメモリ バリアを挿入します。同時に、さまざまなプロセッサのメモリ モデルには異なる長所と短所があるため、異なるプロセッサ プラットフォームのプログラマに一貫したメモリ モデルを提示するために、JMM が異なるプロセッサに挿入する必要があるメモリ バリアの数と種類も異なります。 . 同じではありません。次の図は、JMM が異なるプロセッサ メモリ モデルに挿入する必要があるメモリ バリアの概略図を示しています。
JMM、プロセッサ メモリ モデルと逐次整合性メモリ モデルの関係
JMM は言語レベルのメモリ モデル、プロセッサ メモリ モデルはハードウェア レベルのメモリ モデル、逐次整合性メモリ モデルは理論的な参照ですモデル 。以下は、言語メモリ モデル、プロセッサ メモリ モデル、および逐次整合性メモリ モデルの長所と短所を比較した図です:
上の図からわかるように、4 つの一般的なプロセッサ メモリ モデルは、一般的に使用される 3 つの言語メモリ モデルよりも弱いです。プロセッサ メモリ モデルと言語メモリ モデルは両方とも、逐次整合性メモリ モデルよりも弱いです。プロセッサのメモリ モデルと同様、言語が実行パフォーマンスを追求すればするほど、メモリ モデルの設計は弱くなります。
JMM の設計
JMM 設計者の観点から見ると、JMM を設計する際には 2 つの重要な要素を考慮する必要があります。
プログラマによるメモリ モデルの使用。プログラマは、理解しやすく、プログラムしやすいメモリ モデルを求めています。プログラマは、強力なメモリ モデルに基づいてコードを作成したいと考えています。
メモリモデルのコンパイラとプロセッサの実装。コンパイラーとプロセッサーは、パフォーマンスを向上させるためにできるだけ多くの最適化を実行できるように、メモリー モデルによる制約を最小限に抑えたいと考えています。コンパイラとプロセッサは、弱いメモリ モデルを実装したいと考えています。
これら 2 つの要素は矛盾しているため、JMM を設計する際の JSR-133 専門家グループの中心的な目標は、適切なバランス ポイントを見つけることです。一方では、プログラマーに十分なメモリ可視性の保証を提供する必要があります。コンパイラとプロセッサの制限は可能な限り緩和する必要があります。 JSR-133 がこの目標をどのように達成するかを見てみましょう。
具体的な説明については、前述の円の面積を計算するためのコード例を参照してください:
double pi = 3.14; //A double r = 1.0; //B double area = pi * r * r; //C
A happens- B の前に発生;
B が C の前に発生;
A が C の前に発生操作 A は操作 B の前に行う必要があります。 ただし、プログラム セマンティクスの観点から見ると、A と B を並べ替えてもプログラムの実行結果は変わりませんが、プログラムの実行パフォーマンスも向上します (この並べ替えを許可すると、コンパイラとプロセッサの最適化の制約が軽減されます)。つまり、上記 3 つの事前発生関係のうち、2 と 3 は必要ですが、1 は不要です。したがって、JMM では、事前発生要件で禁止されている並べ替えを次の 2 つのカテゴリに分類します:
プログラムの実行結果を変更する並べ替え。
順序を変更してもプログラムの実行結果は変わりません。
JMM は、これら 2 つの異なる性質の並べ替えに対して、異なる戦略を採用します。
プログラムの実行結果を変更する並べ替えの場合、JMM は、コンパイラーとプロセッサに対して、そのような並べ替えを禁止することを要求します。
JMM は、プログラムの実行結果を変更しない並べ替えについてコンパイラーとプロセッサーに要件を課しません (JMM はそのような並べ替えを許可します)。
以下は JMM の設計図です:
上の図から 2 つの点がわかります: JMM によってプログラマーに提供される前発生ルールは、プログラマーのニーズを満たすことができます。 JMM の事前発生ルールはシンプルで理解しやすいだけでなく、プログラマーに十分強力なメモリ可視性の保証を提供します (上記の A 事前発生 B など、一部のメモリ可視性保証は必ずしも実際に存在するとは限りません)。
JMM では、コンパイラーとプロセッサーに対する制約ができるだけ少なくなります。上記の分析から、JMM は実際に基本原則に従っていることがわかります。つまり、プログラムの実行結果が変更されない限り (シングルスレッド プログラムと正しく同期されたマルチスレッド プログラムを指します)、コンパイラーとプロセッサーは、どのように使用されても最適化されます。たとえば、コンパイラーが注意深く分析した結果、ロックが単一のスレッドによってのみアクセスされると判断された場合、そのロックは削除できます。別の例として、コンパイラーが慎重な分析の結果、volatile 変数が単一のスレッドによってのみアクセスされると判断した場合、コンパイラーは volatile 変数を通常の変数として扱うことができます。これらの最適化によってプログラムの実行結果は変わりませんが、プログラムの実行効率も向上します。
JMM のメモリ可視性保証
Java プログラムのメモリ可視性保証は、プログラムの種類に応じて次の 3 つのカテゴリに分類できます。
シングルスレッド プログラム。シングルスレッド プログラムにはメモリの可視性の問題はありません。コンパイラー、ランタイム、プロセッサーは連携して、シングルスレッド プログラムの実行結果が逐次整合性モデルでのプログラムの実行結果と同じになるようにします。
適切に同期されたマルチスレッド プログラム。適切に同期されたマルチスレッド プログラムの実行には、逐次一貫性が保たれます (プログラムの実行結果は、プログラムが逐次一貫性のあるメモリ モデルで実行された場合と同じになります)。これが JMM の焦点であり、コンパイラとプロセッサの並べ替えを制限することでプログラマにメモリの可視性を保証します。
非同期/誤って同期されたマルチスレッド プログラム。 JMM はそれらに最小限の安全保証を提供します。スレッドの実行時に読み取られる値は、前のスレッドによって書き込まれた値、またはデフォルト値 (0、null、false) のいずれかです。
次の図は、JMM および逐次一貫性メモリ モデルにおけるこれら 3 種類のプログラムの実行結果の類似点と相違点を示しています。
マルチスレッド プログラムが正しく同期されている限り、JMM は、任意のプロセッサ プラットフォームでのプログラムの実行結果が、逐次一貫性のあるメモリ モデルでのプログラムの実行結果と一致することを保証します。
JSR-133 による古いメモリ モデルの修正
JSR-133 は、主に次の 2 つの方法で JDK5 より前の古いメモリ モデルを修正します。
揮発性メモリ セマンティクスを強化します。古いメモリ モデルでは、揮発性変数を通常の変数と並べ替えることができました。 JSR-133 は、揮発性の書き込みと読み取りとロックの解放と取得が同じメモリ セマンティクスを持つように、揮発性変数と通常の変数の並べ替えを厳しく制限します。
final のメモリ セマンティクスを強化します。古いメモリ モデルでは、同じ最終変数の値が複数回読み取られると異なる場合があります。この目的を達成するために、JSR-133 では、final に 2 つの並べ替えルールを追加します。現在、final には初期化の安全性があります。
上記は Java メモリ モデルの詳細な分析: 概要です。その他の関連コンテンツについては、PHP 中国語 Web サイト (m.sbmmt.com) に注目してください。