Flash AS3 - removeChild() используется для полного удаления объекта?

Я создаю игру с астероидами, и в моем основном классе у меня возникают проблемы с пулями, выпущенными кораблем.

Все маркеры относятся к классу "Bullet" и хранятся в массиве "bullets" в основном классе. Когда пули выходят из экрана, вызывается removeBullet(bulletID) в основном классе.

private function removeBullet(id:int)
    {
        removeChild(bullets[id]);
        bullets.splice(id);
    }

В моем классе Bullet у меня есть слушатель enterFrame, который отслеживает "stillHere". Поэтому, как только пуля добавлена ​​на главную сцену с использованием addChild, в моей панели вывода появляется "stillHere".

Моя проблема в том, что даже после того, как я вызываю removeBullet, "stillHere" продолжает появляться в панели вывода, что говорит мне, что объект, который я пытался удалить, все еще остается где-то в памяти.

Что я могу сделать, чтобы полностью избавиться от этого?

2 ответа

Решение

Поскольку вы находитесь в ActionScript, у вас нет прямого контроля над удалением объектов.

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

Однако лучший подход - иметь только один ENTER_FRAME слушатель на всю игру. Для этого нужно будет индивидуально продвигать все элементы игры (корабль, астероиды, пули, обломки и т. Д.). Этот метод удаляет все ваши шансы случайно забыть удалить прослушиватели событий, а также делает код более понятным, поскольку вы можете видеть порядок обновления элементов за определенный промежуток времени.

У меня обычно есть destroy функция в моих временных объектах, которая читает что-то вроде этого:

public function destroy():void {
    stop(); // if it's a MovieClip
    if(parent) parent.removeChild(this);
}

Пока я вызываю эту функцию, а затем удаляю ссылки на объект, он обычно собирается.

По этой причине в моем коде очень редко есть слушатели отдельных объектов.

Сам слушатель события вполне может быть причиной того, что он все еще находится в памяти. Это не хороший способ проверить, было ли что-то собрано или нет.

Кроме того, даже если бы это был хороший способ проверить, был ли объект собран мусором, сбор не является мгновенным процессом. Flash Player запускает gc только тогда, когда ему нужно выделить больше памяти и не удается это сделать.

Предполагая, что у вас нет других ссылок на объект маркированного списка, кроме списка отображения и массива маркеров, того, что вы сделали, достаточно для его сбора мусора.

РЕДАКТИРОВАТЬ: Чтобы ответить на вопрос о том, есть ли способ наблюдать, был ли объект был собран...

Вы можете использовать объект в качестве ключа в словаре со слабым ключом.

private var _dict:Dictionary = new Dictionary(true);
_dict[bullet] = "Bullet is still here...";

Затем, когда вы захотите проверить, существует ли пуля, вы используете цикл for... in для итерации ключей.

for(var key:* in _dict){
    trace(key + " " + _dict[key]);
}

Поскольку ключи со слабым ключом словаря не считаются ссылками для целей сборки мусора, это работает.

Если вы очень обеспокоены утечками памяти, вы можете подумать о записи пула объектов, в который вы помещаете старые объекты маркеров, которые вы удаляете со сцены, и просто повторно используете их снова и снова. Таким образом, вы никогда не допустите, чтобы какие-либо пули собирались мусором, но вы, вероятно, когда-либо создадите небольшое, ограниченное количество пуль (то есть количество пуль, которые пользователь когда-либо видит на экране одновременно в данный момент времени). Это может быть лучшим решением для вас, поскольку пули, вероятно, занимают мало места в памяти, и вы получаете бонус, не заставляя Flash очищать свой мусор. Запуск GC приводит к снижению производительности во время удаления мусора, поэтому с помощью этой меры делать все возможное, чтобы предотвратить даже необходимость в этом, - хорошая вещь.

Другие вопросы по тегам