Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Система удаления ненужных объектов и слушателей (http://www.flasher.ru/forum/showthread.php?t=204878)

KumoKairo 13.11.2013 17:07

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

Конечно, есть вероятность того, что сам автор статьи что-то начудил со ссылками и не удалил неявные, или не отписался от каких-либо событий, и именно поэтому возникает такая двусмысленность. Но к сведению принять все же надо - желательно удалять ссылку не только на какой-то "автономный" кусок программы, но и отписываться от событий и удалять ссылки внутри этого участка программы.

a7s1h1 13.11.2013 17:10

Странно. А у меня, если убрать из ClassName функцию удаления детей (та, что через while), то при удалении ClassName из Main (Main - это родитель ClassName) объект child не удаляется. В следующий раз при создании ClassName у него уже 2 ребёнка. Наверное, всё-таки, где-то остаются какие-то связи, мешающие удалению ClassName сборщиком.
Почитав ответы и порывшись в интернете, я пришёл к выводу (поправьте, если это не так), что лучший способ чистки - это вручную удалять всё при удалении объекта со сцены. Поэтому проверка помещения на сцену не обязательна, можно исходные данные писать в конструкторе, а для удаления объекта и слушателей можно сделать метод destroy(), отзывающийся на REMOVED_FROM_STAGE, в котором поочерёдно
1 - удаляем всех детей (removeChild)
2 - обнуляем все переменные, ссылавшиеся на объекты
3 - убираем всех слушателей
Таким образом, когда объект "прародитель" удаляет всех своих детей, то каждый из этих детей перед тем, как удалиться со сцены, выполняет эти три пункта и т.д. по цепочке.

- Адекватен ли такой подход? (если не брать в расчёт то, что прийдётся вручную забивать в damage() обнуление всех переменных, ссылающихся на объекты)

- В каких случаях обязательно вместо обычного конструктора использовать махинации с init-cleanup через события добавление-удаление со сцены?

- В каких случаях целесообразно при создании объекта использовать ADDED вместо ADDED_TO_STAGE и, соответственно, REMOVED вместо REMOVED_FROM_STAGE?

Добавлено через 2 минуты
Цитата:

Сообщение от KumoKairo (Сообщение 1152235)
Советую обратить внимание так же на эту статью

Не поверите, только что её как раз прочитал) Спасибо.
Возможно, у меня как раз такая проблема. А может, и нет. В любом случае, очень хотелось бы услышать мнение знатоков относительно ручного метода, как описал чуть выше.

Akopalipsis 13.11.2013 17:36

У меня вопрос по теме - обьект обьявлен на уровне класса, затем я в методе создаю обьект и в его конструктор передаю тот обьект, с которого начал вопрос. Следом я помещаю обьект созданный локально в массив и через некоторое время удаляю его. Удалится ли он?

Добавлено через 2 минуты
Был бы очень рад, если бы кто нибудь ответил. С профайлером у меня почему то обьекты живут своей жизнью, а скаут не как не поставлю, у меня виндовс х86, а как я прочёл, нужен х64.

Tails 13.11.2013 17:39

Цитата:

Таким образом, когда объект "прародитель" удаляет всех своих детей, то каждый из этих детей перед тем, как удалиться со сцены, выполняет эти три пункта и т.д. по цепочке.
Не нужно этого всего. Зачем? Вы нагородили лишнего кода и сами себя запутали. Придумали себе проблему на пустом месте.
Удалите всё и напишите нормально, создайте ребёнка в конструкторе и добавте в себя. 1 подписка на enterFrame, и всё! Там кода на пару строк и с памятью всё хорошо будет.

Зачем родителю париться о своих детях, если его с ними и так полностью удалили? Вы тратите лишнее время цп, загромождаете код и только создаёте потенциальные возможности для утечек, не решая при этом никакой проблемы! Ладно, если бы это был какой-то сложный компонент, но у вас то обычные DisplayObject.

KumoKairo,
Ни разу не сталкивался с такой проблемой. Всегда причина всех утечек, больших и маленьких - были по собственной вине.
Автор упомянутой статьи большой уверенности не вселяет. Если утечка и возможна по вине флеш плеера, её как правило, как и любой баг - можно локализовать. Или определить приблизительные условия для её воспроизведения. Фраза "У меня в большом объёме кода где-то возникают утечки" - говорит только о не компетентности самого автора, уж простите.

Akopalipsis,
Объект - он и в африке объект. Это просто "область" данных, которая размещена в памяти программы. А ссылаться на эту область, или на объект, можно и из класса и из экземпляра любого класса и ещё откуда-нибудь. Пока есть ссылка на эту область, не важно откуда, объект - продолжает жить.

пс. Уточню, ссылка в данном случае - возможность внешнего кода "достучаться" до объекта. На объект может ссылаться 100500 других объектов, но если ни один из них не доступен внешне - все отправляются в утиль. Исключением для этого правила являются запущенные таймеры, о которых я писал выше и может быть, ещё какие нибудь редкие внутренние классы флешового апи, о которых сразу предупреждается в справке.
Такая философия.

КорДум 13.11.2013 18:18

К слову, вызвать GC в релиз-плеере тоже можно. Для этого нужно воспользоваться
Цитата:

какие нибудь редкие внутренние классы флешового апи, о которых сразу предупреждается в справке
созданием битмапдаты с последующим вызовом метода dispose() у нее. Но сразу предостерегу тех, кто обрадуется и пойдет юзать сей костыль. Так делать можно, но только в особо крайних случаях, когда ну вообще никакие оптимизации не помогают. Частый вызов GC тоже существенно тормозит приложение.

Akopalipsis 13.11.2013 18:19

Tails Спасибо! я немного запутался, по этому уточню - вот так обьект контайнер удалится?
Код AS3:

package
{
        import flash.display.Sprite;
        import flash.events.Event;
 
        public class Main extends Sprite
        {
                private var _object:Object;
                private var _storage:Array;
 
                public function Main():void
                {
                        if (stage) init();
                        else addEventListener(Event.ADDED_TO_STAGE, init);
                }
 
                private function init(e:Event = null):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, init);
 
                        _storage = new Array();
                        _object = new Object();
                        _storage.push(new Container(_object));
                        _storage.shift();
                }
 
        }
 
}

Код AS3:

package 
{
        public class Container extends Object
        {
                private var _object:Object;
 
                public function Container(object:Object)
                {
                        _object = object;
                }
 
        }
 
}


Tails 13.11.2013 18:20

КорДум,
Да верно, для некоторых конкретных типов данных есть такая возможность. Ещё xml объекты можно диспозить. Но в целом - доступ к gc закрыт.

Akopalipsis,
Да.

Это объявление переменной для экземпляров класса.
Код AS3:

private var _object:Object;

Это объявление переменной для самого класса. В этом варианте, контейнер не удалился бы. Подумайте почему.
Код AS3:

private static var _object:Object;


КорДум 13.11.2013 18:27

Tails, Михалик вроде как год назад писал, что у XML проблема с диспозом частенька: не удаляется он. Вообще да, можно вызывать GC и так, но как бы не напороться на утечку памяти.

Tails 13.11.2013 18:34

КорДум,
В справке написано, что xml становиться доступным для сборки. Ещё вроде Мук писал, что gc не сразу удаляет объекты, и что у него есть некая система меток. Вызовом диспоза xml - мы лишь "отмечаем" объект для удаления, тем самым облегчая работу сборщику, а не делая её за него.

Вообще, тема конечно интересная, я использую xml и их удаление, пока не замечал утечек. Надо-бы поискать эту статью.

a7s1h1 13.11.2013 18:40

Цитата:

Сообщение от Tails (Сообщение 1152243)
Придумали себе проблему на пустом месте. Удалите всё и напишите нормально, создайте ребёнка в конструкторе и добавте в себя. 1 подписка на enterFrame, и всё! Там кода на пару строк и с памятью всё хорошо будет.

Наверное, я просто делаю неверные выводы из получаемой информации.
Спасибо за помощь, пожалуй, так и сделаю. Единственное, что я так и не понял - как лучше удалять объекты в случаях, когда мы не удаляем конкретный объект целенаправленно, а в случае удаления родителя. Ведь даже если дети удаляются автоматически с родителем, то ведь слушатели детей всё равно надо удалять отдельно, или нет?

В любом случае, надо, видимо, попробовать написать всё заново, или хотя бы тщательно проверить. Но теперь обойдусь конструктором, без всяких added_to_stage и init, и каждому объекту пропишу метод destroy() с удалением слушателей и обнулением ссылок - на GC больше надежды нет, вручную вернее будет.


Часовой пояс GMT +4, время: 04:33.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.