0

Java のパフォーマンスに関する簡単な質問です。ループを書くと

for(int i=0;i<n;++i) buffer[(k++)%buffer.length]=something;

その中で何かが自明ではないデジタルフィルターです。このコードでは、書き込みごとにモジュロ演算を行います。とにかく Java VM がそれをチェックするので、これは少しばかげているように感じます。したがって、ArrayIndexOutOfBounds を使用した構成の方が高速であると想定します (バッファーには 1'000'000 個の数値が含まれているため、オーバーフローが頻繁に発生することはありません)。

int i;
try
  {
  for(i=0;i<n;++i,++k) buffer[k]=something;
  }
catch (ArrayIndexOutOfBounds e)
  {
  k=0;
  for(;i<n;++i,++k) buffer[k]=something;
  }

3 つ目の解決策は、どの時点でオーバーフローするかを事前に計算してから、ループを手動で 2 つに分割することです。ループがどこまで進むことができるかを決定するコードは、768 サンプルごとに実行されるため、その観点からすると、catch メソッドよりも遅くなる可能性があります。

ここでの問題は、コードのばかげた重複は別として (パフォーマンスの祭壇で喜んで犠牲にします)、コードが増えていることです。そして、Java は小さなルーチンほど最適化されていないように見えることがよくあります。

私の質問は次のとおりです。最もパフォーマンスの高い戦略は何ですか? このタイプの構成を経験した人はいますか? また、両方のコンストラクトの Android デバイスでのパフォーマンスに光を当てられる人はいますか?

4

1 に答える 1

3

あなたの答えはあなたのターゲットプラットフォームに依存します。Androidタグを追加したので、Dalvikと(たとえば)Nexus4の観点から回答します。

まず、ARMv7-Aアーキテクチャは整数除算命令を提供しません。モジュラスは、ループを通過するたびにソフトウェアで計算されるため、少し遅くなります。(これが、ハッシュテーブルに2の累乗サイズを使用するのが最適な理由です。modではなくビットマスクを使用できます。)

第二に、例外をスローすることはコストがかかります。VMは例外オブジェクトを作成し、現在のスタックのスナップショットで初期化する必要があります。即時のオーバーヘッドに加えて、後でクリーンアップする必要があるX個のオブジェクトを作成しているため、VMが計算の途中で停止してガベージを収集しなければならない可能性が高くなります。

第3に、一般的に言えば、内側のループから引き出すことができる計算はすべて勝利を意味するため、ループの反復ごとに配列のオーバーランを手動でテストすることは不十分です。回避できる場合は、ループヘッダーまたは本体にkvs.のテストを追加しないでください。length(JITコンパイラーはこのようなことをするかもしれません-配列インデックスが配列の終わりから決して離れないことがわかるなら、要素ごとの境界チェックをする必要はありません。)

あなたがしていることとそれを何回しているのかという(まだ少し漠然とした)感覚に基づいて、私は最良の選択肢はループの前の「ブレーク」位置を計算し、必要な数を繰り返すことだと思いますの時間。

これが実際にどうなるか知りたいです。:-)

于 2012-12-14T01:02:48.650 に答える