AS3, сборка мусора и многоуровневые спрайты со слушателями - PullRequest
3 голосов
/ 25 марта 2011

All

Если я создаю спрайт, и этот спрайт содержит множество дочерних спрайтов (которые сами также содержат дочерние спрайты), нужно ли мне беспокоиться о сборщике всего или только родительском спрайте? Что делать, если к спрайту ребенка или внука прикреплены слушатели?

Например, допустим, у меня есть класс (подкласс Sprite), который создает экран в приложении.

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

Итак, в моем приложении у меня есть это:

var myscreen:MyScreenClass = new MyScreenClass();
this.addChild(myscreen);

Позже, когда пользователь завершит работу с этим экраном, я удаляю его:

this.removeChild(myscreen);
myscreen = null;

Это все, что мне нужно сделать? Или мне нужно рекурсивно пройти через myscreen, удалив все его дочерние спрайты и прослушиватели событий?

Другими словами, если вы GC родитель, все ли это дети, внуки, правнуки и т. Д. Также GCed?

(Для чего бы то ни было, я использую слабые ссылки в своих слушателях событий ...)

Заранее спасибо!

Ответы [ 2 ]

10 голосов
/ 26 марта 2011

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

Мусор с разметкой метокКоллектор работает путем обхода графа объекта, начиная с самого верхнего объекта (т. е. рабочей области).Отрежьте все пути к части графика, и весь этот подграф будет иметь право на сбор, независимо от каких-либо ссылок, которые подграф имеет между собой.

Сначала давайте рассмотрим только иерархию списка отображения без событий:

var clip:Sprite = new Sprite();
addChild(clip);
var clip2 = new Sprite();
clip.addChild(clip2);
// cleanup
removeChild(clip);
clip = null;
clip2 = null;

Внутренний дочерний клип2 будет собирать мусор, даже если мы не удалили его из родительского элемента с помощью clip.removeChild(clip2).Так как мы удалили все ссылки на родительский clip и явную ссылку clip2, нет доступа к нему, поэтому он будет собирать мусор.Поэтому нет необходимости removeChild клипов-потомков.Просто убедитесь, что вы удалили все внешние ссылки на них (в данном случае clip2).

Теперь давайте представим некоторые события:

var clip:Sprite = new Sprite();
addChild(clip);
clip.addEventListener(MouseEvent.CLICK, someListener);
var clip2:Sprite = new Sprite();
clip.addChild(clip2);
clip2.addEventListener(MouseEvent.CLICK, someOtherListener);
// cleanup -- the same!
removeChild(clip);
clip = null;
clip2 = null;

Вы можете подумать, что вам нужно удалитьслушатели событий, но на самом деле это не обязательно. addEventListener создает ссылку от диспетчера к слушателю .То есть добавление слушателей к дочерним объектам не помешает их сборке мусора.В этом случае addEventListener делает ссылку с клипа на корень, а клип2 на корень.Когда происходит сборка мусора, маркер не может перейти от корня к клипу, даже если этот слушатель находится там.Ссылка идет в другом направлении , от клипа к корню!Таким образом, объекты по-прежнему будут собирать мусор.Следовательно, в этом случае нет необходимости удалять слушателей.Тем не менее, это не помешает сделать это, если вы не уверены.

Единственный способ, которым слушатели могут предотвратить сборку мусора, это если дочерний клип прослушивает родительский клип:

// from inside clip
root.addEventListener(MouseEvent.CLICK, someHandler);

Этот слушатель создает ссылку из корня в клип, поэтому вы должны либо удалить эту ссылку, либо использовать слабые ссылки.Поскольку вы используете слабые ссылки, вам не нужно об этом беспокоиться.

Это действительно много, чтобы отслеживать, и легко ошибиться, поэтому это хорошопотренируйтесь, чтобы удалить слушателей, когда вы закончите с ними .Вы всегда будете в безопасности, если уберете их.Это очень важно со странными нативными событиями, которые Flash отправляет вам, такими как Event.ENTER_FRAME и KeyboardEvent.KEY_DOWN, но не из-за проблем со сборкой мусора: даже если клип не имеет ссылок и имеет право на сбор, он будет продолжать получатьСобытия ENTER_FRAME, пока сборщик мусора не запустится в какой-то неопределенной точке в будущем.Поэтому вы ВСЕГДА должны удалять слушателей ENTER_FRAME.

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

Если вы хотите посмотреть, что происходит, может быть полезно использовать инструменты профилировщика в Flash Builder, FlashDevelop или FDT длявзгляните на использование памяти.Вы также можете использовать вызов System.gc();, чтобы заставить GC работать в режиме отладки, если вы хотите проверить эти идеи.

...