Что такое сборка мусора и как вы это делаете в ActionScript 3.0? - PullRequest
4 голосов
/ 21 июня 2009

Я программирую на ActionScript около 6 лет, но никогда не слышал о термине «сборка мусора», пока не вышел AS3. Почему мы должны беспокоиться об этом сейчас, и никогда раньше? И что именно? Из того, что я прочитал / услышал, это как-то связано с управлением / утечками памяти и т. Д. - и даже , о которых я не понимаю, кроме того, что оно связано с производительностью .

Я недавно запустил сайт для моего друга художника, и это было сделано в AS3. Я замечаю, что это занимает много ресурсов. Очевидно, это то, что я хотел бы улучшить. Я предполагаю, что это как-то связано с тем, что не происходит сборка мусора ?! К сожалению, я не имею ни малейшего представления о том, с чего начать в этом отношении, так как я чувствую, что мне нужно лучшее понимание того, что это такое и как делать это конкретно в AS3.

Для любопытных вот URL: http://www.jeffperrott.com

Ответы [ 6 ]

6 голосов
/ 21 июня 2009

Сборщик мусора - это часть среды выполнения (в вашем случае проигрыватель Flash или AIR), которая очищает неиспользуемую память. У ActionScript всегда была сборка мусора, как и у всех языков сценариев (например, javascript, perl, ruby ​​и т. Д.), Вы просто не видите, чтобы это обсуждалось для AS.

Основная идея заключается в том, что каждому созданному объекту требуется некоторая память, а ваши переменные сохраняют ссылку на эти объекты. Память объекта не «высвобождается» обратно в пул доступной памяти, пока на нее больше нет ссылок. Сборщик мусора отслеживает, какие объекты имеют ссылки на них, и через различные промежутки времени будет восстанавливать память объектов с нулевыми ссылками (то есть без переменных, указывающих на него, поэтому никакой код даже не сможет найти его для его использования). Если есть какие-либо ссылки *, память объекта не может быть восстановлена, если какая-то часть вашего кода решит использовать ее в будущем.

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

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

function registerHandler(neverReleased:Object) {
    ...
    addEventHandler(function (e:Event) {
            ...
        });
}

Вызов сборщика мусора напрямую - это почти всегда плохо (тм), сборщик мусора во Flash / Flex очень хорош. Сначала выясните, где хранятся ваши объекты, и отпустите их, чтобы GC работал по собственному графику.

* За исключением циклических ссылок , что немного выходит за рамки этого ответа.

2 голосов
/ 21 июня 2009

Каждый раз, когда вы используете ключевое слово «new» для создания объекта, вы размещаете заявку на куске памяти [1]. Допустим, вы делаете вывод, написав var exampleUint:uint = new uint();. ActionScript говорит компьютеру «эй ... мне нужно, как ... четыре байта памяти.», На что компьютер отвечает «хорошо, круто, используйте четыре байта, начиная с [некоторый адрес памяти, например, 0x7B3208C1]» [2] , Поэтому, когда вы говорите var someString:String = "blah";, вы запрашиваете место в памяти, заполняете его некоторой информацией (в данном случае это "blah"), создаете метку (в данном случае это someString) и bind метка для этого пространства в памяти.

Теперь метка фактически не ассоциируется с самими данными, она ассоциируется с местом в памяти, содержащим данные. Это должно показаться запутанным, потому что это так, но по определенным причинам это имеет смысл. Все объекты в ActionScript являются ссылочными типами, что означает, что объект содержит адрес памяти некоторого фрагмента данных, а не сами данные. Это отличается от объектов типа value , где метка связана с самими данными. Не беспокойтесь о деталях типов значений, потому что это не в ActionScript, поэтому для ваших целей я включаю его исключительно для контраста. ОК, запутался? Вероятно, так и должно быть, поскольку весь этот абзац излишне специфичен и, возможно, даже не нужен, но старайтесь держать его в затылке, потому что может как-то иметь отношение к вашей проблеме.

Теперь, когда эта метка исчезла (например, она выходит за пределы scope , поэтому теперь someString не имеет смысла), удаляется только метка someString. Так что для этого примера, если вы скажете someString = null;, строка "blah" на самом деле все еще находится в памяти, но метка someString не ссылается на этот фрагмент информации, она ссылается на адрес памяти нулевого объекта (опять же, подробности). Нам нужен способ указать компьютеру: «Вы знаете, какой кусок памяти [whatSize] я требовал, начиная с [whatAddress]? Что ж, теперь я покончил с этим, чтобы кто-то другой мог использовать этот кусок памяти». Коллекция Gabage - это автоматический процесс восстановления памяти, на который вы претендовали, не беспокоясь об этом самостоятельно. В языках без сборки мусора new имеет ключевое слово дополнение, которое специально освобождает память, связанную с объектом [3], но ActionScript не имеет этого; ты просто берешь кусок памяти и забываешь об этом.

Где-то вдоль строк, вы, возможно, создали другую переменную и сослались на этот фрагмент данных, var someOtherString:String = someString;, поэтому мы не можем просто сказать: «Хорошо, метка someString исчезла, так что давайте избавимся от данных что он ссылается ", потому что мы не знаем наверняка, что someString является единственной ссылкой на эти данные. Метод, в котором это делается, различается в зависимости от языка и системы сборки мусора, но основное действие в ActionScript заключается в следующем: время от времени (особенно если Flash в настоящее время занимает много памяти) сборщик мусора просматривает все объекты в текущем SWF и находит все объекты, на которые нет ссылок [4]. Таким образом, для нашего предыдущего примера, если someString было единственной ссылкой на строку "blah" и someString выходит из области видимости, то "blah" не связан ни с одной меткой и поэтому полностью недоступен для Flash. В следующий раз, когда будет запущен сборщик мусора, он обнаружит это и затем сообщит системе, что он сделал с этим фрагментом памяти.

Теперь, конкретные детали вашей конкретной проблемы трудно сказать, не глядя на источник, но я могу вам сказать, что одна из вещей, которая часто вызывает проблемы, - это прослушиватели событий. Иногда вы можете создать функцию и добавить ее в качестве прослушивателя событий. Теперь само событие имеет ссылку на эту функцию [5], поэтому, если функция выходит из области видимости, есть ссылка на нее, и функция не может быть собрана сборщиком мусора (помните, функции являются объектами в ActionScript). Вы можете либо удалить обработчик событий вручную, вызвав removeEventListener (я бы не рекомендовал это сделать), либо установить параметр useWeakReference в ваших вызовах на addEventListener () на true. Слабая ссылка не распознается сборщиком мусора, поэтому установка useWeakReference в true предотвращает ситуацию, когда у вас есть функция, которая должна быть подобрана сборщиком мусора, но это не потому, что кто-то ссылается на него как на слушателя событий. Судя по большому количеству слушателей mouseEvent в вашем проекте, это может быть причиной. Если у вас есть Flex Builder, вы можете использовать профилировщик, чтобы увидеть, сколько у вас закрытий методов; если они поднимаются и никогда не падают, это, вероятно, ваша проблема.

[1]: имейте в виду, что это также относится к ситуациям, когда вы создаете объект без использования ключевого слова new, например, если вы пишете var exampleInt:int = 5;.
[2]: Я выбрал uint, потому что все uint имеют одинаковый размер, поэтому я могу с уверенностью сказать, что знаю, что это будет четыре байта. Строки разные; они занимают объем памяти, пропорциональный количеству содержащихся в них символов, поэтому было бы немного двусмысленно использовать String для обоих примеров.
[3]: ключевое слово ActionScript delete не для этой цели, поэтому не пытайтесь использовать его таким образом, даже если это имело бы логический смысл и было бы очень полезно.
[4]: Flash использует стратегию стиля mark-and-sweep , более подробные сведения о которой можно прочитать здесь . [5]: На самом деле, это полужирная ложь, потому что метод addEventListener использует замыкания , но у меня довольно слабое понимание этого, поэтому я не могу свести его к английскому обычному человеку.

0 голосов
/ 22 июня 2009

Просто чтобы помочь вам понять, почему вы не слышали об этом раньше, в предыдущих версиях AS GC был тесно связан со списком отображения. После того как вы удалили объект со сцены, он больше не существовал (вместе с дочерними объектами), и любая ссылка на него была обращена в нуль. Такое поведение, как вы, возможно, уже знаете, в AS3 совершенно противоположное. Удачи!

0 голосов
/ 21 июня 2009

Добавление к ответу Чедвика:

Если вы добавляете EventEandler к изображению, но не removerEventHandler, когда изображение больше не отображается, память, занятая изображением, не может быть восстановлена ​​сборщиком мусора.

0 голосов
/ 21 июня 2009

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

Примером является Native C ++. Прежде чем программисты на C ++ смогут действительно многое сделать с приложением, им нужно подготовить почву для работы с памятью. Они просят у ОС память, они добавляют выделения, они добавляют объекты и данные в память, позже они удаляют объекты и данные, они распределяют память, очищают ее и снова высвобождают в ОС.

С помощью GC GC выполняет всю эту работу за вас. Все, что вам нужно сделать, это сказать GC (обычно путем создания экземпляра объекта), что вы планируете использовать память, и GC выясняет, сколько памяти вам нужно, запрашивает ОС для этого, выделяет и добавляет ваши данные. Затем он время от времени проверяет, использует ли ваше приложение этот объект. Если это не так, он удаляет объект, распределяет его, очищает и возвращает обратно в ОС. Все это сделано для вас, чтобы вы, программист, могли просто сосредоточиться на своей программе. Примером этого является VB 6.0 и C # / VB.NET.

РЕДАКТИРОВАТЬ: Это очень упрощенное объяснение. На самом деле, здесь много чего, но этот ответ должен ответить на основной вопрос, заданный здесь.

0 голосов
/ 21 июня 2009

Я ничего не знаю о реализации AP3, но кто-то должен опубликовать это:)

http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)

По сути, вы работаете с указателями (ну, ссылками) на данные. Ссылка, которая выходит из области видимости, будет удалена. Всякий раз, когда никакие ссылки не указывают на данные, данные будут помечены для сбора мусора. Ваш GB-поток (процесс или демон) со временем освободит все ресурсы, использованные для выделения помеченных данных.

...