2011-12-21 3 views
3

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

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

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

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

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

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

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

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

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

+0

Я не вижу упоминания о тестировании/профилировании. Это на самом деле узкое место в производительности? – Thomas

+0

за ваш бонусный вопрос, ArrayList, построенный без параметра начальной емкости, сначала выделяет пространство для 10 объектов в списке и растет по начальной емкости, когда это необходимо. Вы можете вызвать 'trimToSize', чтобы сэкономить место. – Pedantic

+0

Для бонусного вопроса ArrayList по умолчанию делит пропускную способность 10. http://stackoverflow.com/a/4666050/340068 –

ответ

6

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

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

+0

Спасибо, я подумал об этом методе и фактически использовал что-то вроде этого, но был отложен после небольшого исследования. Похоже, что функция get (i) медленнее для итерации по сравнению с итераторами. Компромисс с сохранением ассигнований я полагаю .... Возможно, придется экспериментировать – makar

+2

@makar. Фактически для 'ArrayLists'' get' будет так же быстро или быстрее, чем использовать итераторы. Он напрямую ссылается на позиционный элемент базового массива. –

+0

это не было сделано до Java 5. Итераторы навсегда существовали в java. – jtahlborn

2

Я отвечу на бонусный вопрос первый: Да, 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).

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

+0

+1 Для микрооптимизации –

+0

Спасибо за подробный ответ. Я знал о связанных рисках, связанных с возвратом итератора одного экземпляра, но был счастлив соблюдать правила, если это означало прекращение распределения. Что касается вашего другого аспекта, я был достаточно осторожен, чтобы не делать никаких итераций в игре, поэтому, видя, что все эти неявные выделения извергаются, немного расстраивает! Я сопротивлялся стремлению сделать слишком много оптимизаций слишком рано, но почувствовал, что если бы я мог просто поменять свои ArrayLists на другой тип, это было бы быстрым решением, не имеющим никакого отношения ни к чему другому. Но точка взята! – makar

+0

* не делать никаких ассигнований. не итераций. – makar

Смежные вопросы