2010-12-07 73 views
5

我的代碼基本上沒有分配空間,但GC在60fps時每隔30秒運行一次。使用DDMS檢查應用程序的分配情況顯示,分配的ALOT爲SimpleListIterator。還有一些東西被分配,因爲我使用Exchanger分配免費遊戲

SimpleListIterator來自每個循環for (T obj : objs) {}。我的印象是,編譯器/譯者會優化那些不使用迭代器的類型支持它(我基本上只使用ArrayList),但似乎並非如此。

如何避免分配所有這些SimpleListIterators?一個解決方案是切換到定期for循環for (int i = 0; i < size; ++i) {}但我喜歡每個環:(

的另一種方法將是擴展的ArrayList它返回一個Iterator是隻分配一次。

的第三種方式我入侵一起使用被重用Iterator它返回一個Collection一個靜態輔助功能,我砍死像這樣在一起,但鑄造感覺非常hackish的和不安全的應該是線程安全的,雖然我使用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循環中獲取值所需的一個額外行更好... – 2010-12-07 14:18:19

+0

已採取的措施。猜猜我應該咬在一起,併爲每個循環溝? :( – alexanderblom 2010-12-07 14:23:25

+0

我已經使用了「擴展ArrayList,它返回一個只能分配一次的迭代器」版本,需要注意的一點是(與你提到的所有迭代類型一樣)是嵌套迭代,在我的版本中我添加了一個顯式的「釋放「方法,並可以理智地檢查迭代器是否已經被使用......以這種方式捕獲了一個令人討厭的bug另一個注意事項:讓Iterator.remove拋出一個UnsupportedOperationException是合法的 – Darrell 2010-12-07 14:30:35

回答

2

可能最好的方法是使用裝飾設計。創建一個在構造函數中使用集合的類,並通過調用被包裝的類並重新使用返回的迭代器來實現Iterable接口。

0

另外兩種避免分配迭代器的方法。 第一種是使用一個回調成語:

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亞型實施可迭代和迭代器,但是這清楚地表明集合本身的光標位置作爲狀態。