Уборка мусора в ActionsScript 3

Написано 30/04/2008

Небольшая заметка про уборщика мусора, опубликованная вот тут. Я лишь вольно перевёл.

***

Все Java-разработчики отлично знаю об уборщике мусора. Знают, как этот уборщик работает. А вот у флэшеров, особенно начинающих, может возникнуть проблема с пониманием работы этого механизма, а соответственно приводить к утечкам памяти.

А знать работу этого механизма необходимо. Уборщик мусора в ActionScript 3, он же garbage collector (прости, Юра, сейчас не о твоём блоге речь), работает двумя различными путями для выяснения какой из объектов подлежит удалению из памяти: это так называемый “mark&sweep” (пометить и вымести) метод и “reference counting”.

Вот этот самый “reference counting” (“счётчик) метод очень прост для понимания: подсчитывается использование свойств каждого объекта во время выполнения приложения. Счётчик то приростает на единичку, то уменьшается на ту же единицу – это происходит при использовании свойств объекта другими объектами. Когда счётчик доходит до нуля, то сборщик мусора может удалить этот объект из памяти.

Метод “mark&sweep” стартует из root-объекта приложения и проверяет все свойства объекта, пытаясь достичь каждого в “дереве свойств”. И если какое-либо свойство будет недостижимо, то плеер может удалить такой объект из памяти. Это делается для того, чтобы из root-объекта можно было получить доступ к любому свойству объекта.

Счётчик – быстрее и проще. “Mark&sweep” был представлен в восьмом флэш-плеере, он более эффективен, но проверка “дерева свойств” очень затрата для процессора.

Как наверняка знают флэшеры, наибольшая вероятность утечки памяти возникает от listener’ов. ActionScript 3 дает возможность разработчикам создавать слушателей с “хрупкими” weak-свойствами, и работа с которыми для счётчика тяжка.

//последний параметр - weakReference-флаг
object.addEventListener("eventName", listenerFunction, false, 0, true);

В данном случае мы не рискуем получить объект, который будет невозможно удалить из памяти; в любом случае у нас есть возможность удалить листенер:

object.removeEventListener("eventName", listenerFunction);

Также, мы можем использовать ChangeWatcher:

var watcher:ChangeWatcher = ChangeWatcher.watch(object, "property", listenerFunction);

Мы не должны забывать вызывать unwatch-метод, когда “смотрелка” нам больше не нужна:

watcher.unwatch();

В Java возможно вызвать уборщика мусора, используя две простые инструкции:

Runtime r = Runtime.getRuntime();
r.gc();

Во флэше нет такой простой возможности, но имеется маленьких хак:

private function gcHack():void
{
       try

       {
              var lc1:LocalConnection = new LocalConnection();
              var lc2:LocalConnection = new LocalConnection();

              lc1.connect('name');
              lc2.connect('name');
       }
       catch (e:Error)
       {
       }
}

Документированной функции для этого дела не найдено.

***

Извините, если что не так – переводил “на ходу”