Бесплатная раздача

Мой код в основном освобождается, однако GC работает каждые 30 секунд или около того, когда он составляет 60 кадров в секунду. Проверка приложения с DDMS для выделения показывает, что SimpleListIterator из SimpleListIterator выделяется. Есть также некоторые вещи, которые выделяются, потому что я использую Exchanger .

Для каждого цикла SimpleListIterator используется for (T obj : objs) {} . У меня создалось впечатление, что компилятор / переводчик оптимизирует те, которые не будут использовать итераторы для типов, которые его поддерживают (в основном я использую ArrayList), но это, похоже, не так.

Как я могу избежать выделения всех этих SimpleListIterators ? Одним из решений было бы переключиться на регулярные для циклов 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() {} } } 

Вы не должны использовать их для игр в Android. Я думаю, что это официальное видео также говорит об этом.

Вероятно, наилучшим подходом было бы использовать дизайн Decorator. Создайте класс, который берет коллекцию в конструкторе и реализует интерфейс Iterable, вызывая обернутый класс и повторно используя возвращенный итератор.

Два дополнительных подхода для исключения размещения итераторов. Во-первых, нужно использовать идиом обратного вызова:

 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); } } 

Конечно, это то же самое, что реализация Iterable и Iterator в вашем подтипе ArrayList, но это явно показывает местоположение курсора как состояние самой коллекции.