2016-10-21 5 views
0

最終的に私は知っている限り、変数/オブジェクトをキャッシュすることができることをCPUに伝えています(CPUとはCPUとはまったく異なります)。x86 CPUは本当にコアキャッシュL1を実行しています。 次の例では、オブジェクトmyObjectFinalがfinalとして設定されているため、CPUがキャッシュして内部の値を変更します。 myObjectが変更されることが保証されていないことを意味しますか?最終とメモリリーク

finalを設定すると参照が壊れ、CPUがキャッシュすることにしましたか?

myObjectを変更した場合、キャッシュされた最終結果もまた変更されることが保証されますか?

// thread 1 
volatile MyObject myObject = new MyObject(); 
// thread 2 
final MyObject myObjectFinal = myObject; 
myObjectFinal.setData(1); 
// thread 1 
myObject.setData(2); 

多分、コードは私の意図を正確には伝えません。だから、主な質問は:変更可能なオブジェクトを最終的にまたは揮発性にすることは、オブジェクトがCPUによってどのようにキャッシュされるかに影響を与えるかどうかです。それでは、変更可能なオブジェクトに対してfinalまたはvolatileを使用する必要があるときは、

CPUは変更可能なオブジェクトをキャッシュするか、またはfinal/volatileは絶対に影響を与えず、コーディングの一貫性のみに使用されますか?

+0

あなたの質問は 'final'についてのものよりも' volatile'キーワードに関するものです。あなたの(メンバー)変数が 'volatile'宣言されていると、JVMは他のスレッドの変更が現在のスレッドで見えるようにします。 'volatile'キーワードなしでは、' final'キーワードを無視しません。 –

+1

**オブジェクトmyObjectFinalがfinal **に設定されています - いいえ、 'Object'が' final'に設定されていない場合、**オブジェクト参照**が 'final'として設定されています。一般的に、「volatile」と「final」はプリミティブ型の可視性に意味があり、他のシナリオでは明示的な 'synchronization'が必要です。 –

+0

@Sabir明らかに、私はオブジェクト参照にファイナルを置いています!オブジェクトをコピーする場合、またはプリミティブを使用する場合、私の質問は意味をなさないでしょう。あなたのコメントはまったく役に立たない。もう一度同期は揮発性とは異なります。この質問は、コードの一部をアトミックにしないCPUでのキャッシュについてです。 – chris

答えて

0

finalは、初期化後に値を変更できないことを意味します。

最後の変数が割り当てられると、常に同じ値が格納されます。最終的な変数がオブジェクトへの参照を保持している場合、オブジェクトの状態によってオブジェクトの状態が変更される可能性がありますが、変数は常に同じオブジェクトを参照します。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4

あなたがmyObjectFinalを再割り当てない限り、悪いは、あなたが複数のスレッドから同じオブジェクトを変更した場合は、同期が必要になりますが、

を起こりません。 (volatileを使用しないでください)

まず、オブジェクトの向きを取り除いてください。オブジェクトは仮想コンストラクトです。私たちはレジスタやキャッシュのような低レベルのものについて話しています - プリミティブのみです(すべてのクラスをプリミティブのセットに減らすことができます)。

キャッシュが必要な理由は簡単です。 メモリはちょっと恐ろしいです。そのため、メモリアクセスの回数を最小限に抑えることが考えられます。

は、次のコードを考えてみましょう。あなたの通常のコンピュータの内部

1. x=0; 
2. if (x == 1) 
3. x++ 

今(レジスタ最適化なし)、このような何かを起こる

1. write 0 into a register 
    write the register into the memory 
2. read x from the memory into a CPU-register 
    compare it with 1 and go to 3 or 4 
3. read x from the memory into a CPU-register 
    increment register 
    write the register into the memory 

冗長メモリ操作の多くを...しかし、あなたそれらを排除することができる

1. write 0 into a register 
    write the register into the memory 
2. compare the register with 1 and go to 3 or 4 
3. increment register 
    write the register into the memory 

私たちはregiにxの値を保持しますスターでは、なぜすべての変数をレジスタに保持しないのですか?まず最初に、利用可能なレジスタがたくさんあるので、そこにすべてのレジスタを格納することはできません。その変数をレジスタに保持するのは一時的です。(スコープ内など) もう1つの問題は、他のコアおよび/またはデバイスがレジスタから読み取れないことです。変数を再読み込み/書き戻しする必要があります。

変数をfinalとして宣言すると、変数は変更されません。したがって、変数はレジスタに格納することができ、矛盾の問題は発生しません。しかし、これは他のスレッドがメモリにも格納されているため、変数にアクセスできないことを意味するものではありません。メモリ内の値が常に有効であることを保証します。しかし、最終的なものであろうとなかろうと、すべての変数は短期間レジスタに格納することができます。複数スレッド/コアの一貫性を保証したい場合は、同期ツールを使用してレジスタからメモリに強制的に書き戻す必要があるのです。

しかし、実際のCPUキャッシュは完全に異なるトピックです。ハードウェア側で実行される完全な透過的なシステムです。メモリアクセスパターンの影響を受けます(実際にアセンブリで低レベルの低レベルを実行しない限り)。 CPUキャッシュは基本的にすべてのバイトをキャッシュします。

+0

すでにJLSを参照しているので、関連する参照先は次のとおりです。[JLS 17.5 final field semantics](https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5 )。最後のフィールドは絶対にCPUキャッシングに影響を与えますが、JLSではCPUレジスタに最終フィールド値をキャッシュすることを明示的に指定することさえあります。 –

+0

はいレジスタですが、明らかに影響を受けるL1コアキャッシュ – Domso

+0

CPUレジスタ私は、メモリリークを考えると、L1よりも他のスレッド/コアではさらにアクセスできないと思います。質問は、正確にキャッシュされていない場所でのメモリリークに関するものです。 – chris

関連する問題