2011-12-21 7 views
3

私は最初のゲームをAndroidで書いていますが、ゲームの最適化に関する長時間のプレゼンテーションを見た後、割り当てを確認しています。 for(Object o:m_arrayList)のための暗黙的なイテレータを作成するときに、ArrayListを作成したものとは別に、すべてのゲーム内の割り当てを取り除くことができました。JavaでのArrayListイテレータの割り当てを防止する

私のゲームオブジェクト、AIエンティティなどはすべて使いやすさのためにこれらに格納されているので、これらの繰り返し/割り当てはかなり少ないです。

私のオプションは何ですか?

  • 私は、理論的には賢明なupperboundsを指定し、配列を使用していますが、私はArrayListに、そのような存在としての機能を好きなことは、クリーンでシンプルなコードを維持削除できます。

  • ArrayListをオーバーライドし、それが使用されるたびに新しいイテレータタイプを割り当てるのではなく、クラスメンバーを返すiterator()の独自の実装を提供します。

私は使いやすさのためにオプション2に行くことを好むだろうが、私は少しこれを持っていたし、問題に遭遇した。誰も私が上記のオプション2で説明したものの例を持っていますか?私はジェネリッククラスから継承する際に問題を抱えていましたが、明らかに型の衝突がありました。

これに対する2番目の質問は、これらの割り当てを避けるための他のオプションがありますか?

そして、私は、ArrayListが特定の量(ctorまたはシフト可能な値のいずれかで指定された)のメモリスロットを事前に割り当てているかどうか知っていますか、あなたはその範囲内にとどまりますか?クリア()後も?

ありがとうございました。申し訳ありませんがありますが、この情報は多くの人に役立つと思います。

+0

私はテスト/プロファイリングの言及はありません。これは実際にパフォーマンスのボトルネックですか? – Thomas

+0

あなたのボーナスの質問ごとに、初期容量パラメータなしで構築されたArrayListは、最初にリスト内の10個のオブジェクトのためのスペースを割り当て、必要に応じて初期容量で増加します。スペースを節約するために 'trimToSize'を呼び出すことができます。 – Pedantic

+0

ボーナスに関する質問では、ArrayListはデフォルトで10の容量を割り当てます。 @sthomasoverflow.com/a/4666050/340068 –

答えて

6

位置の繰り返しを使用します。

それは事前割り当てのためのJava 5

前に行われていた方法です

for (int i = 0, n = arrayList.size(); i < n; ++i) 
{ 
    Object val = arrayList.get(i); 
} 

ArrayList arrayList = new ArrayList(numSlots); 

またはランタイム

arrayList.ensureCapacity(numSlots); 

そしてボーナスのために - >http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html

+0

おかげさまで、私はこの方法について考えていましたが、実際にはこのようなものを使用していましたが、ちょっとした調査をした後に延期されました。 get(i)関数はイテレータと比較して反復処理が遅くなっているようです。私が想定していた配分のトレードオフは·························· – makar

+2

@makar実際には 'ArrayLists'の' get'はイテレータを使うより速く、あるいは速くなります。基本となる配列の位置要素を直接参照します。 –

+0

これはJava 5より前にはこのようにしていませんでした。イテレータはJavaで永遠に使用されていました。 – jtahlborn

2

私は最初のボーナスの質問にお答えします:はい、ArrayListは、事前に割り当てスロットを行います。これは、所望の数のスロットを引数として取るコンストラクタを有する。 new ArrayList<Whatever>(1000)clearはスロットを割り当て解除しません。

共有イテレータリファレンスを返すことにはいくつかの問題があります。主な問題は、イテレータを最初の要素にいつリセットするかを知る方法がないことです。以下のコードを検討:

CustomArrayList<Whatever> list = ... 
for (Whatever item : list) { 
    doSomething(); 
} 
for (Whatever item : list) { 
    doSomethingElse(); 
} 

CustomArrayListクラスは、その共有反復子は、2つのループ間にリセットされるべきであることを知る方法がありません。あなたが呼び出しの間イテレータをリセットしたくないを行う。この場合

for (Whatever first : list) { 
    for (Whatever second : list) { 
     ... 
    } 
} 

:あなただけiterator()すべてのコールでそれをリセットする場合は、ここで問題があるでしょう。

@Alexander Progrebnyakの答えはおそらくIteratorを使わずにリストを反復する最良の方法です。高速ランダムアクセスがあることを確認してください(つまり、LinkedListは使用しないでください)。

ここでは、かなり重いマイクロ最適化を行っていることを指摘したいと思います。私はあなたのコードをプロファイルし、イテレータを割り当てることが本物の問題であるかどうかを調べる前に、多くの時間を費やすことをお勧めします。ゲームでさえ、最適化が必要なものだけを最適化する必要があります。そうしないと、長時間の操作で数ミリ秒のシェイビングを頻繁に行うことができます。

+0

+1マイクロ最適化の場合 –

+0

詳細な回答ありがとうございます。私は、インスタンスイテレータが1つ返されるという関連するリスクを認識していましたが、割り当てを停止することを意味する場合には必要なルールを遵守することができました。あなたのもう一つの点に関しては、私はゲームで何も反復しないように全力で慎重に考えています。そのような暗黙的な割り当てのすべてを見ることは少しイライラしています!私はあまりにも早く多くの最適化をやる気に抵抗しましたが、ArrayListsを別の型にスワップするだけであれば、他のものとは何の関係もなく迅速に修正されるでしょう。しかし、ポイントを取った! – makar

+0

*割り当てを行いません。反復ではありません。 – makar

関連する問題