我的代码基本上是免费分配的,但是当60fps时,GC每30秒运行一次。使用DDMS检查应用程序以进行分配显示已分配了大量SimpleListIterator
。还有一些东西被分配,因为我使用Exchanger
。
SimpleListIterator来自每个循环for (T obj : objs) {}
。我的印象是编译器/翻译器会优化那些不使用迭代器来支持它的类型(我基本上只使用ArrayList),但似乎并非如此。
如何避免分配所有这些SimpleListIterators
?一种解决方案是切换到常规for循环for (int i = 0; i < size; ++i) {}
,但我喜欢每个循环:(
另一种方法是扩展ArrayList,它返回一个只分配一次的Iterator
。
我一起攻击的第三种方法是使用静态辅助函数,该函数返回Collection
,它正在重用Iterator
。我一起攻击了这样的东西,但铸件感觉非常黑暗和不安全。它应该是线程安全的,因为我使用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() {}
}
}
答案 0 :(得分:4)
您不应该在Android游戏中使用每个游戏。 我认为这official video也谈到了这一点。
答案 1 :(得分:2)
可能最好的方法是使用Decorator设计。创建一个类,它在构造函数中获取一个集合,并通过调用包装类并重用返回的迭代器来实现Iterable接口。
答案 2 :(得分: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));
}
}
}
这种方法仍然需要一个Handler实例来接收回调,但是这肯定会减少分配,例如,当你试图访问几个列表的元素时。
第二种方法是使用游标习语:
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的子类型上实现Iterable和Iterator相同,但这清楚地将光标位置显示为集合本身的状态。