2

私はアンドロイドのクラスを読んでいてSparseArray、次のメソッドに出くわしました:

public void removeAt(int index) {
    if (mValues[index] != DELETED) {
        mValues[index] = DELETED;
        mGarbage = true;
    }
}

明らかに、これも書かれている可能性があります。

public void removeAt(int index) {      Or   public void removeAt(int index) {
    if (mValues[index] != DELETED) {            mValues[index] = DELETED;
        mValues[index] = DELETED;               mGarbage = true;
        if (!mGarbage)                      }
            mGarbage = true;         
    }                                
}                                    

Androidの開発者は、配列のルックアップmValues[index]は配列の書き込みよりも高速であると信じていたようですが、変数のルックアップは変数の書き込みよりも高速ではありませんでした。

これは本当に本当ですか?それはVMに依存しますか、それともコンパイル言語の一般的な知識ですか?

4

3 に答える 3

5

確かに、右側のバージョンは同等ではありません。値が変更されたかどうかmGarbageに関係なく、 trueに設定されるためです。

左側はオリジナルと同じですが、意味がありません。

基本的に、既存の値がDELETEDを許可しているかどうかを確認するという副作用を見逃していると思います。メソッドが実際に効果を発揮した場合にのみmGarbage、 trueに設定できます。これは、配列からの読み取りのパフォーマンスとは何の関係もありません。

于 2011-08-31T10:03:29.080 に答える
2

これはVMに大きく依存し、この特定のコードはDalvik VM用に調整されていると思います(または、Apache Harmonyがたまたま実装したものです)。

覚えておくべきことの1つは、書き込みは常にキャッシングとクロススレッドの相互作用に関連するコストを意味しますが(つまり、正しく機能するにはメモリバリアが必要になる場合があります)、読み取りははるかに簡単です。

于 2011-08-31T10:07:01.017 に答える
1

プロセッサとJVMの実装に大きく依存しますが、この仮定はおそらく正しいでしょう。

一般的な理由は、配列と変数の関係ではなく、メモリアクセスパターンの関係です。

  • mGarbageは、レジスタまたはL1キャッシュのいずれかで、現在のオブジェクトのフィールド値である場合、ローカルにキャッシュされる可能性が非常に高くなります。数サイクル前に仮想メソッドルックアップのようなことを行うために、おそらくオブジェクトをキャッシュに置いておくだけです。何かがローカルにキャッシュされている場合、読み取りと書き込みの間に大きな違いはありません。
  • mValues [index]は、ローカルにキャッシュされる可能性が低い配列ルックアップです(特に、配列が大きい場合、または散発的にしかアクセスされない場合)。非ローカルキャッシュからの読み取りは、ロック/メモリ競合の問題があるため、通常は書き込みよりも高速であるため、それを回避できる場合にのみ読み取りを実行するのが理にかなっています。この効果は、マシンにコアが多く、コードに同時実行性が高いほど強くなります。
于 2011-08-31T10:10:17.637 に答える