Форум 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=122388)

2K WebStudio 10.03.2009 12:36

Удаление объектов из иерархии отображения
 
Представим себе такую последовательность действий:

1. Создаем объект (сохранив на него ссылку)
2. Отслеживаем наступления некоторого события (не связанного с помещением или удалением объекта в/из иерархии отображения)
3. Добавляем объект в иерархию отображения
4. Удаляем объект из иерархии отображения
5. Удаляем ссылку на объект, созданную на первом шаге

По сути flash удалит объект, когда ему это понадобится, если ссылок на объект не осталось.
Вопрос такой: понятно, что события, обозначенные в шаге 2 не наступят. Но удалится ли объект? Т.е. будет ли считаться, что мы стерли ВСЕ ссылки на объект?

И еще момент: представим, что в наш объект были размещены другие объекты (ссылки на которые не сохранились), за которыми так же следили (addEventListener). После проделанных шагов 4 и 5, будут ли под-объекты считаться пригодными для выбрасывания?

Надеюсь, достаточно четко объяснил суть вопроса.

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

dimarik 10.03.2009 13:25

Мне не совсем понятно, почему события в шаге 2 не наступят, но Вам виднее. Объект не удалится, потому что был шаг 1.

По моменту. addChild оставляет ссылку на ребенка у родителя в списке детей. Т. o. объекты не будут считаться пригодными для выбрасывания до тех пор, пока не произойдет removeChild.

2K WebStudio 10.03.2009 13:53

Цитата:

Сообщение от dimarik (Сообщение 804285)
Мне не совсем понятно, почему события в шаге 2 не наступят, но Вам виднее. Объект не удалится, потому что был шаг 1.

Почему не удалится, если мы удаляем ссылку на нее и делаем reremoveChild()?

Цитата:

Сообщение от dimarik (Сообщение 804285)
По моменту. addChild оставляет ссылку на ребенка у родителя в списке детей. Т. o. объекты не будут считаться пригодными для выбрасывания до тех пор, пока не произойдет removeChild.

Но ссылки на родителя ведь уже нет. Почему не удаляются дети?

iflamberg 10.03.2009 14:19

флеш не настолько умный. Все ссылки лучше занулять(включая удаляемых детей). И обязательно удалять всех слушателей.

2K WebStudio 10.03.2009 14:35

Цитата:

Сообщение от iflamberg (Сообщение 804309)
флеш не настолько умный. Все ссылки лучше занулять(включая удаляемых детей). И обязательно удалять всех слушателей.

мда.. неприятно..
как обойти всех детей - я знаю.
тогда вопрос: как зная объект, найти всех назначенных слушателей (т.е. пару тип и значение слушателя)?

etc 10.03.2009 15:04

Цитата:

Сообщение от 2K WebStudio (Сообщение 804317)
мда.. неприятно..
как обойти всех детей - я знаю.
тогда вопрос: как зная объект, найти всех назначенных слушателей (т.е. пару тип и значение слушателя)?

Ну вы же знаете, у кого и зачем подписались?

2K WebStudio 10.03.2009 15:11

Цитата:

Сообщение от __etc (Сообщение 804338)
Ну вы же знаете, у кого и зачем подписались?

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

спасибо.

и можно на "ты".

etc 10.03.2009 15:13

Цитата:

Сообщение от 2K WebStudio (Сообщение 804339)
в общем случае - нет.

Как это? Я вот знаю где и на что я подписываюсь у объекта и при его удалении всё отписываю.

2K WebStudio 10.03.2009 15:18

Цитата:

Сообщение от __etc (Сообщение 804340)
Как это? Я вот знаю где и на что я подписываюсь у объекта и при его удалении всё отписываю.

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

etc 10.03.2009 15:20

В правильно начатом проекте проблемы отписывания от событий в принципе не возникнет.

2K WebStudio 10.03.2009 15:23

Цитата:

Сообщение от __etc (Сообщение 804343)
В правильно начатом проекте проблемы отписывания от событий в принципе не возникнет.

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

etc 10.03.2009 15:25

Удаление детей должен произвести сам удаляемый объект.

2K WebStudio 10.03.2009 15:27

Цитата:

Сообщение от __etc (Сообщение 804346)
Удаление детей должен произвести сам удаляемый объект.

как и удаление их слушателей.

iflamberg 10.03.2009 15:38

в общем случае, я делаю метод destroy, который запускает destroy у всех детей, а потом зануляет свои ссылки и убивает слушателей. Уж свои-то листенеры объект должен знать.

2K WebStudio 10.03.2009 15:46

Цитата:

Сообщение от iflamberg (Сообщение 804350)
в общем случае, я делаю метод destroy, который запускает destroy у всех детей, а потом зануляет свои ссылки и убивает слушателей. Уж свои-то листенеры объект должен знать.

зануляет ссылки на себя? как он узнает о них?

iflamberg 10.03.2009 16:17

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

etc 10.03.2009 16:26

Цитата:

Сообщение от 2K WebStudio (Сообщение 804348)
как и удаление их слушателей.

Если родитель слушает события детей, то он должен от детей отписаться.

2K WebStudio 10.03.2009 16:57

Цитата:

Сообщение от iflamberg (Сообщение 804361)
зануляет ссылки внутри себя. Убить ссылку на него - задача уже его родителя.
Непонимаю в чем проблемы, любой программист, который учился программированию на cpp или даже pascal имеет понимание о том, как освободить память.

изучаю специфику флеша. мало ли что.
меня просто удивила формулировка вашего ответа - потому и уточнил.

Цитата:

Сообщение от __etc (Сообщение 804364)
Если родитель слушает события детей, то он должен от детей отписаться.

естественно.

Румеев 11.03.2009 23:15

Присоединяюсь к __etc.
Но сделаю замечание: занулять все ссылки, удалять всех детей и делать кучу других лишних действий (в общем случае) - это гемор чистой воды.
Нужно занулять (и снимать слушатели) только то, что действительно необходимо ;)
Деструкторы в классах тогда будут занимать больше чем сами классы ))
Зануления и удаления могут немного ускорить процесс "mark" у GC (garbage collector), не более.
Важно четко и правильно понимать как флэш работает с памятью. Тогда проблем с "нужно/не нужно" не будет.

P.S. Какие бы профи не были в команде разрабов, без Flex Profiler порой не обойтись ;)
P.P.P.P.P.S. ну и те кто пишут свои проги в Flash IDE, не прогеры... )))) гы

s8000_1 12.03.2009 02:51

Цитата:

Сообщение от iflamberg
флеш не настолько умный. Все ссылки лучше занулять(включая удаляемых детей).

Неверно. Флэш умный.

Цитата:

Сообщение от 2K WebStudio
есть ли необходимость удалять всех детей

Нет такой необходимости.

Цитата:

Сообщение от __etc
Удаление детей должен произвести сам удаляемый объект.

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

Цитата:

Сообщение от iflamberg
в общем случае, я делаю метод destroy, который запускает destroy у всех детей, а потом зануляет свои ссылки

Смысл? Эта работа бесполезна :) Как уже сказали выше, такой подход может ускорить GC, и все.

Цитата:

Сообщение от iflamberg
Непонимаю в чем проблемы, любой программист, который учился программированию на cpp или даже pascal имеет понимание о том, как освободить память.

Так AS3 не паскаль или cpp. В AS3 есть сборщик мусора как бы.


В общем-то проверьте профайлером:

Код AS3:

package{
        import flash.display.*;
        import flash.events.*;
        public class Test extends Sprite{
                var mcs:Array;
                function Test(){
                        graphics.beginFill(0xFF00FF);
                        graphics.drawRect(0,0,50, 50);
                        mcs = new Array();
                        var mc:Sprite;
                        for (var i:uint = 0; i< 100; i++){
                                mc = new Sprite();
                                mc.addEventListener(MouseEvent.CLICK, onChildClick);
                                mcs.push(mc);
                        }
                }
                private function onChildClick(e:Event):void{
                        trace (e.currentTarget);
                }
        }
}

Код AS3:

package {
        import flash.display.*;
        import flash.events.*;
        public class MemoryTest extends Sprite {
                var bt:Sprite;
                var bt1:Sprite;
                var mc:Sprite;
                function MemoryTest() {
 
                        bt = new Sprite();
                        bt.graphics.beginFill(0);
                        bt.graphics.drawRect(0,0,100,100);
                        stage.addChild(bt);
 
                        bt1 = new Sprite();
                        bt1.graphics.beginFill(0xFF0000);
                        bt1.graphics.drawRect(0,0, 100,100);
                        bt1.x = 100;
                        stage.addChild(bt1);
 
                        bt.addEventListener(MouseEvent.CLICK, createObjects);
                        bt1.addEventListener(MouseEvent.CLICK, removeObjects);
 
                }
                function createObjects(e:Event):void {
                        if (mc) {
                                return;
                        }
                        mc = new Test();
                        mc.addEventListener(MouseEvent.CLICK, clickListener);
                        mc.y = 100;
                        stage.addChild(mc);
                }
                function removeObjects(e:Event):void {
                        if (!mc) {
                                return;
                        }
                        stage.removeChild(mc);
                        mc = null;
                }
                function clickListener(e:Event):void{
                }
        }
}

Все прекрасно удаляется из памяти и без ручного обнуления всего и вся. Утечек памяти нет. Версия плеера 10.12.36.

Насчет удаления слушателей надо понимать лишь, что такое слушатель, и как оно работает. А работает оно как-то так:
http://www.javaworld.com/javaworld/j...04-events.html
child.addEventListener(event, parentFunc) в массив _listeners ребенка кладет ссылку на parentFunc. А т. к. это дело изолировано в ребенке, то ничего казалось бы не помешает флэшу удалить спокойно child из памяти, если на него не осталось ссылок. Но из-за особенности флэшовских событий (bubbling) в родителе тоже возможно сохраняются ссылки на ребенка - мое предположение. Поэтому:
Цитата:

Сообщение от __etc
Если родитель слушает события детей, то он должен от детей отписаться.

Хотя ИМХО это банально перестраховка (см. пример для профайлера выше), ибо по-хорошему методы addChild и removeChild класса DisplayObject должны быть умными и удалять всех лишних слушателей из Event Flow автоматически. Может быть в прошлых версиях плеера был какой-то баг, связанный с удалением объектов? __etc, почему именно-то Вы везде рекомендуете удалять слушателей?

Кстати, может кто знает, нет ли где-нибудь статьи, в которой описана модель событий флэша на очень детальном уровне? Т. е. фактически как написать класс EventDispatcher идентичный флэшовому.

BlooDHounD 12.03.2009 11:09

s8000_1, мдя ... ни какой ГЦ не имеет отношения ни к какой событийной модели, и уж тем болие к её баблингу. Ваш пример не связывает больше 3х кусочков различных частей приложения, поэтому поймать тут, что-то типа утечки будет сложно... но если вдруг получится так, что Вам придётся передать хотя бы на одного ребёнка Test ссылку, вся ваша конструкция целиком повиснет в памяти после удаления, а не только тот несчастный ребёнок. и так как Денис разрабатывает приложение состоящие не из 2х классов, что-то мне подсказывает, что он не раз встречался с ситуацией, что случайно не убитый слушатель тянет за собой, целую ветку своих родителей, которые в свою очередь тянут за собой своих детей.

2K WebStudio 12.03.2009 12:07

интересное обсуждение.
должен заметить, что в Муке ничего про удаление слушателей как и детей нет. Точнее там просто не затрагивается тема удаления под детей в освобождении памяти.

iflamberg 12.03.2009 12:27

я пишу игрушки. На as3. Там постоянно создаются объекты, удаляются, эти объекты взаимодействуют с другими объектами, держат в себе ссылки на них. И постоянно ловлю утечки памяти. В больших MMO на флеш - и timeZero, и в Dofus, я тоже вижу, как с каждым часом клиент сжирает все больше и больше оперативы. Могу сказать уверенно, что GC во флеше очень неторопливый и совершенно тупой.

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

iNils 12.03.2009 13:36

Цитата:

Хотя ИМХО это банально перестраховка (см. пример для профайлера выше), ибо по-хорошему методы addChild и removeChild класса DisplayObject должны быть умными и удалять всех лишних слушателей из Event Flow автоматически.
То есть, если я не добавил объект на сцену, то и получить события от него не могу?

s8000_1 12.03.2009 14:54

Цитата:

Сообщение от BloodHouD
ни какой ГЦ не имеет отношения ни к какой событийной модели, и уж тем болие к её баблингу. Ваш пример не связывает больше 3х кусочков различных частей приложения, поэтому поймать тут, что-то типа утечки будет сложно... но если вдруг получится так, что Вам придётся передать хотя бы на одного ребёнка Test ссылку, вся ваша конструкция целиком повиснет в памяти после удаления, а не только тот несчастный ребёнок. и так как Денис разрабатывает приложение состоящие не из 2х классов, что-то мне подсказывает, что он не раз встречался с ситуацией, что случайно не убитый слушатель тянет за собой, целую ветку своих родителей, которые в свою очередь тянут за собой своих детей.

Да я не про GC и событийную модель. Я про то, что сама событийная модель тривиальна при отсутствии флэшовых фич и надо понять, как она работает. Я предположил, что из-за этих фич разные ссылки на объект и слушатель события создаются в родителях, родителях родителей и т. п. - из-за этого и надо удалять все вручную.

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

iNils, лишние слушатели - это те, которые ловят событие не в target-фазе.
А если Вы не добавляете объект на сцену, эти слушатели не создадутся.

BlooDHounD 12.03.2009 15:40

s8000_1, как у Вас всё утопично ... в жизни бы так :)

s8000_1 12.03.2009 15:47

BlooDHounD, но Вы разве не согласны, что ручное удаление - перестраховка или "правило хорошего тона", а не необходимость? И что EventDispatcher можно переписать самому и понять, кто где может создавать ссылки на слушателей и объекты, испускающие события.

Я сам-то лично удаляю слушателей и детей (их по возможности) на случай "вдруг забуду обнулить где-то внешнюю ссылку".

BlooDHounD 12.03.2009 16:19

это необходимость. в команде разработчиков нельзя гарантировать, что второй разработчик соблюдёт все нюансы Вашей безалаберности.

iflamberg 12.03.2009 16:40

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

2K WebStudio 12.03.2009 18:08

Цитата:

Сообщение от iflamberg (Сообщение 804958)
столько разлагольствования, чтобы в итоге выяснить, что в большом проекте все занулять необходимо

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


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

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