2010-12-07 12 views
5

私のコードは基本的に割り当てが無料ですが、GCは60fpsで30秒ごとに実行されます。割り当てのためにDDMSを使ってアプリをチェックすると、SimpleListIteratorが割り当てられていることがわかります。私はExchangerを使用しているので、割り当てられているものもあります。割り当て無料ゲーム

SimpleListIteratorは各ループfor (T obj : objs) {}から来ます。私は、コンパイラ/トランスレータが、イテレータをサポートする型に対してイテレータを使用しないように最適化するという印象を受けましたが(私は基本的にArrayListのみを使用します)、それはそうではないようです。

これらをすべて割り当てるのを避けるにはどうすればいいですか?SimpleListIterators?一つの解決策は、ループfor (int i = 0; i < size; ++i) {}ために正規に切り替えることであろうが、私は、各ループ:(

別の方法として、一度だけ割り当てられIteratorを返すのArrayListを拡張するであろう。

私は一緒にハッキングされた第三の方法を好きIteratorを再利用しているCollectionを返す静的なヘルパー関数を使用している私は一緒にこのような何かをハッキングしたが、鋳造は非常にハックして危険な感じそれは私がThreadLocalを使用するようかかわらず、スレッドセーフである必要があり、以下を参照してください:。。?

public class FastIterator { 
    private static ThreadLocal<Holder> holders = new ThreadLocal<Holder>(); 

    public static <T> Iterable<T> get(ArrayList<T> list) { 
     Holder cont = holders.get(); 

     if (cont == null) { 
      cont = new Holder(); 

      cont.collection = new DummyCollection<T>(); 
      cont.it = new Iterator<T>(); 

      holders.set(cont); 
     } 

     Iterator<T> it = (Iterator<T>) cont.it; 
     DummyCollection<T> collection = (DummyCollection<T>) cont.collection; 

     it.setList(list); 
     collection.setIterator(it); 

     return collection; 
    } 

    private FastIterator() {} 

    private static class Holder { 
     public DummyCollection<?> collection; 
     public Iterator<?> it; 
    } 

    private static class DummyCollection<T> implements Iterable { 
     private Iterator<?> it; 

     @Override 
     public java.util.Iterator<T> iterator() { 
      return (java.util.Iterator<T>) it; 
     } 

     public void setIterator(Iterator<?> it) { 
      this.it = it; 
     } 
    } 

    private static class Iterator<T> implements java.util.Iterator<T> { 
     private ArrayList<T> list; 
     private int size; 
     private int i; 

     @Override 
     public boolean hasNext() { 
      return i < size; 
     } 

     @Override 
     public T next() { 
      return list.get(i++); 
     } 

     @Override 
     public void remove() { 

     } 

     public void setList(ArrayList<T> list) { 
      this.list = list; 
      size = list.size(); 
      i = 0; 
     } 

     private Iterator() {} 
    } 
} 
+1

ええ、あなたが正しく理解していれば、ハッキング反復子は、 'for'ループで値を取得するために必要な1行余分なものよりも優れていますか? –

+0

Point taken。私はちょうど一緒に噛んで各ループの溝を取るべきだと思いますか? :( – alexanderblom

+0

私は "一度だけ割り当てられた反復子を返すextends ArrayList"を使用しました。あなたが言及しているすべての反復スタイルで注意しなければならないことの一つはネストされた反復です。 releaseメソッドを使用して、イテレータがまだ使用されていないことを確認することができます...もう1つの注意:Iterator.removeにUnsupportedOperationExceptionをスローするのは合法です。 – Darrell

答えて

4

Androidゲームでは、それぞれに使用しないでください。 私はこれについてもofficial videoが話していると思います。

+0

私はすべてのループを通常のforループに変換することに決めました。 – alexanderblom

2

おそらく最も良いアプローチは、デコレータデザインを使用することです。コンストラクタ内でコレクションを受け取り、ラップされたクラスを呼び出し、返されたイテレータを再利用して、Iterableインターフェイスを実装するクラスを作成します。

+1

私は、この提案の中心はイテレータを最初に返すreset()メソッドを持つことだと考えています。 –

0

イテレータの割り当てを避けるための2つの追加の方法。 まず、コールバックイディオムを使用することです:

public interface Handler<T> { 
    void handle(T element); 
} 

public interface Handleable<T> { 
    void handleAll(Handler<T> handler); 
} 

public class HandleableList<T> extends ArrayList<T> implements Handleable<T> { 
    public void handleAll(Handler<T> handler) { 
    for (int i = 0; i < size(); ++i) { 
     handler.handle(get(i)); 
    } 
    } 
} 

たとえば、あなたはいくつかの要素を訪問しようとしているとき、このアプローチは、まだコールバックを受信するハンドラのインスタンスが必要ですが、これは間違いなく割り当てを減らすことができますリスト。

第二のアプローチは、カーソルのイディオムを使用することです:

public interface Cursor<T> { 
    void reset(); 
    boolean next(); 
    T current(); 
} 

public class CursoredList<T> extends ArrayList<T> implements Cursor<T> { 
    private int _index = -1; 

    public void reset() { 
    _index = -1; 
    } 

    public boolean next() { 
    return ++_index >= size(); 
    } 

    public T current() { 
    return get(_index); 
    } 
} 

確かに、これは、ArrayListのあなたのサブタイプに反復処理可能とIteratorを実装と同じですが、これは明らかに、コレクション自体の状態としてカーソル位置を示してい。