Предотвращение выделения для итераторов ArrayList в Java - PullRequest
3 голосов
/ 21 декабря 2011

Таким образом, я нахожусь в процессе написания своей первой игры для Android, и после долгой презентации об оптимизации для игр я проверял свои ассигнования. Мне удалось избавиться от всех внутриигровых выделений, кроме тех, которые были сделаны в моем ArrayList, когда он создает неявный итератор для соглашения for (Object o: m_arrayList).

Существует довольно много таких итераций / распределений, поскольку все мои игровые объекты, аи-сущности и т. Д. Хранятся в них для простоты их использования.

Так, каковы мои варианты?

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

  • Переопределите ArrayList и предоставьте мою собственную реализацию iterator (), которая возвращает член класса, а не выделяет новый тип итератора при каждом его использовании.

Я бы предпочел перейти к варианту 2 для простоты использования, но я немного подумал и столкнулся с проблемами. У кого-нибудь есть пример того, что я описал в варианте 2 выше? У меня были проблемы с наследованием от универсального класса, очевидно, конфликты типов.

Тогда возникает второй вопрос: есть ли другие способы избежать этих распределений?

И я предполагаю в качестве дополнительного вопроса: кто-нибудь знает, если ArrayList предварительно выделяет количество слотов памяти на определенную величину (указанную либо в ctor, либо в виде некоторого изменяемого значения), и ему никогда не потребуется выполнять какие-либо другие выделения, если Вы остаетесь в этих пределах? Даже после очистки ()?

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

Ответы [ 2 ]

6 голосов
/ 21 декабря 2011

Использовать позиционную итерацию.

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

Вот как это было до Java 5.

Для предварительного распределения.

ArrayList arrayList = new ArrayList( numSlots );

или во время выполнения

arrayList.ensureCapacity( numSlots );

А для бонуса -> http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html

2 голосов
/ 21 декабря 2011

Сначала я отвечу на бонусный вопрос: Да, ArrayList предварительно распределяет слоты. Он имеет конструктор, который принимает желаемое количество слотов в качестве аргумента, например, new ArrayList<Whatever>(1000). clear не освобождает слоты.

Возврат общей ссылки на итератор имеет несколько проблем. Основная проблема в том, что у вас нет возможности узнать, когда итератор должен быть сброшен до первого элемента. Рассмотрим следующий код:

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

Класс CustomArrayList не может знать, что его общий итератор должен быть сброшен между двумя циклами. Если вы просто сбросите его на каждый вызов на iterator(), то у вас возникнет проблема:

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

В этом случае вы не хотите сбросить итератор между вызовами.

@ Ответ Александра Прогребняка, вероятно, является лучшим способом перебора списка без использования Iterator; просто убедитесь, что у вас есть быстрый произвольный доступ (т.е. никогда не используйте LinkedList).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...