Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Вопрос по Garbage Collector (http://www.flasher.ru/forum/showthread.php?t=149534)

VitaliyKrivtsov 27.01.2011 06:04

Вопрос по Garbage Collector
 
задался вот таким вопросом: "Если в приложение загружается изображение или мувик (не важно, что именно ) и после загрузки нужно удалить loader, то как правильно (если так можно выразится) удалить этот loader, что бы он не завис в памяти с концами". Почитал не много немало литературы по этой теме, в частности заглянул в книгу Мука, вообщем написано везде, что нужно удалить все ссылки на объект а потом обнулить, но как быть в случае, когда нужно, например, загрузить картинку а после удалить loader, но при этом у нас есть ссылка на битмап, удаляем все слушатели , обнуляем loader , выводи в трейс и получаем null, то есть то к чему стремились, но мне не до конца понятно, удалится из памяти сборщиком мусора loader или нет ? И, наверное, из-за того, что есть ссылка на одно из его свойств, а точнее на свойство contentLoaderInfo.
Вот кусок кода в пример:
Код AS3:

private function  loadImage (  ):void {
    var loader:Loader = new Loader( );
    loader.load( new URLRequest("1.jpg") );
    loader.contentLoaderInfo.addEventListener( Event.INIT, initHandler );
}
 
private function initHandler( e:Event ):void
{
    var loader:Loader = Loader( e.target.loader );
    var byteArray:ByteArray = ByteArray( e.target.bytes );// а вот и ссылка )
    var bitmap:Bitmap = Bitmap( loader.content );// а вот еще одна ссылка )        //
    loader.contentLoaderInfo.removeEventListener( Event.INIT, initHandler );
    loader = null;// равно теперь null       
}

То есть у нас две ссылки на свойство объекта, не на сам объект конечно. Но если все-таки объект удаляется, то удаляются и все значения свойств объекта, значит из памяти должны очистится Bitmap и ByteArray, но это не может произойти из-за, что есть на них ссылки, и свою очередь, ничего на самом деле так и не удалилось. Если я что-то не так сказал о процессе сборки мусора, исправьте пожалуйста.

olexandr 27.01.2011 06:49

По идее лоадер должен удалиться при следующем вызове GC.
Грубо говоря, этот пример работает по тому же принципу:
Код AS3:

var arr:Array = [0,1,2];
var a:int = arr[0];
arr = null;

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

dimarik 27.01.2011 11:38

Попытаюсь порассуждать.
Лоадер никуда не денется и GC не может его удалить. Bitmap, как DisplayObject, имеет ссылку на LoaderInfo, который содержит ссылку на Loader.
Код AS3:

trace(e.target.loader == e.target.loader.content.loaderInfo.loader); // true

Если загружать свф, то у всех его визуальных объектов будет ссылка на loaderInfo и, соответственно, loader.
Т.о. пока существует хоть один визуальный объект, загруженный через данный Loader, экземпляр этого лоадера не будет уничтожен.

Добавлено через 18 минут
Не. Даже не так )

Пока существует ссылка на ApplicationDomain, в который лоадер загрузил классы, то будет существовать и сам лоадер. О, как! Кстати, так как картинка является экземпляром Bitmap класса без имени, то "выдернуть" ее класс непосредственно из ApplicationDomain и сделать еще один экземпляр не представляется возможным. Но это можно сделать через ссылку на конструктор BitmapData.

В своих экспериментах с байткодом я загружал картинку, оборачивал ее бинарные данные в именованный класс и, вуаля! Имеем картинку, которую можно в любой момент инстанцировать по ApplicationDomain#getDefinition().

Добавлено через 1 час 22 минуты
Если будет существовать корневой объект (ссылка DisplayObject#root указывает на него), то можно получить ссылки на loaderInfo и его loader. Для загруженных через Loader изображений корневым объектом является сам Bitmap. Опять же это говорит в пользу того, что loader не уничтожается.

cleptoman 27.01.2011 13:11

не лоадер, а Кощей бессмертный получается. т.е. чтобы убить лоадер нужно сделать тройное сальто.

VitaliyKrivtsov 28.01.2011 22:09

olexandr, то есть, если ссылка на другой объект через свойство первого объекта сохраняется в другом объекте - первый будет удален из памяти.
Тогда в случае с loader, сам loader мог бы быть удален, а значение bitmap и byteArray сохранилось бы.
Вернусь к Вашему примеру, а именно в второй строчке
Код AS3:

var arr:Array = [0,1,2];
var a:int = arr[0];

значение присваивается, но это не ссылка на arr[0], если я не ошибаюсь, arr должен удалится,
а вот если это ссылка на одно из свойств объекта, то ссылка ведет на тот участок памяти в котором и есть наш объект по ссылке, и при следующем обращении к bitmap мы обращаемся напрямую к объекту типа данных Bitmap минуя loader и его свойство loaderInfo, и это значит, что loader может быть удален со своими свойствами сохраняя при этом bitmap, но тогда зачем такое удаление объекта, если все что с ним связано не удаляется полностью. Тогда вообще не понятно, что удаляется. Или удаляется, то что не было сохранено прежде по ссылке через loader, а все остальное прежде в памяти будет сидеть.
Пожалуйста, уважаемые форумчане, укажите путь праведный. Я уже сам запутался и в одиночку не разберусь.
olexandr, вот еще, если сделать вот так:
Код AS3:

 var oneArray:Array = new Array("a", "b", "c");
 var twoArray:Array = oneArray;// ссылка на oneArray
 oneArray = null;           
 trace(twoArray); // Output: a, b, c, но мы же удалили oneArray, а значения  twoArray выводятся так как 
 // будто ничего и не происходило, oneArray хоть и был занулен, но так и не удалился поскольку ссылка на // него есть

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

Psycho Tiger 28.01.2011 23:02

Очень интересная тема.
dimarik, я гружу все Bitmap`ы в текущий ApplicationDomain, т.к. коллапса идентификаторов по getDefinition никак не произойдёт. Но
Цитата:

Пока существует ссылка на ApplicationDomain, в который лоадер загрузил классы, то будет существовать и сам лоадер.
То есть мои Loader`ы не удаляются?
Это очень грустная новость. Что можешь посоветовать для загрузки "мимолетных" картинок, которые могут легко появится на экране и так же легко исчезнуть? Создавать каждый раз для картинки дочерний ApplicationDomain мне кажется совсем не хорошей идеей. Для групп картинок "на сеанс", вроде зашли в комнату - увидели лица людей, вышли, "убили" домен - как-то идея тоже чем-то не нравится.

mayakwd 28.01.2011 23:45

Пользуйтесь пожалуйста профайлером, все вопросы отпадут.

Наглядный тест:

Код AS3:

package {
        import flash.display.Bitmap;
        import flash.display.Loader;
        import flash.display.LoaderInfo;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.MouseEvent;
        import flash.net.URLRequest;
        import flash.utils.Dictionary;
 
        public class LoaderTest extends Sprite {
 
                protected var dict : Dictionary = new Dictionary(true);
 
                public function LoaderTest() {
                        addEventListener(Event.ENTER_FRAME, enterFrameHandler);
 
                        var loader : Loader = new Loader();
                        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
                        loader.load(new URLRequest("http://www.flasher.ru/forum/image.php?u=21620&dateline=1288193880"));
 
                        dict[loader] = true;
                }
 
                private function enterFrameHandler(event : Event) : void {
                        var b : Boolean = true;
                        for (var prop : * in dict) {
                                trace(prop);
                                b = false;
                        }
                        if (b) {
                                trace("deleted");
                        }
                }
 
                private function completeHandler(event : Event) : void {
                        var loader : Loader = (event.target as LoaderInfo).loader;
                        var bitmap : Bitmap = loader.content as Bitmap;
                        var sprite : Sprite = new Sprite();
 
                        sprite.addChild(bitmap);
                        sprite.addEventListener(MouseEvent.CLICK, clickHandler);
 
                        addChild(sprite);
 
                        loader.unloadAndStop(true);
                }
 
                private function clickHandler(event : MouseEvent) : void {
                        var spr : Sprite = event.target as Sprite;
                        spr.removeEventListener(MouseEvent.CLICK, clickHandler);
 
                        while (spr.numChildren) {
                                spr.removeChildAt(0);
                        }
 
                        removeChild(spr);
                }
        }
}

С использованием new LoaderContext(false,ApplicationDomain.currentDomain) ничего не меняется, так что с ApplicationDomain промашка, или я не до конца понял мысль dimarik'а.
Смотреть тест надо в профайлере с веселой кнопочкой "run gc"

saikspaik 29.01.2011 00:03

mayakwd опередил )
Профайлер избавит тебя от неизвестности, так как в нем можно не ждать пока GC решит освободить память, а запустить его принудительно и посмотреть на результат.
Профайлер есть во Flex и FlashDevelop, это из тех что я знаю.

Psycho Tiger 29.01.2011 00:26

Спасибо всем, теперь я узнал что такое профайлер.
А на самом деле замечание такое сказал весьма авторитетный человек и я уверен что слова его ну пустые.
Флеш плееров много, в одной из проблема может иметь место. Остается дождаться комментариев.

Но за то что вы провели тесты и сказали что в какой-то фп всё ок — спасибо )

mayakwd 29.01.2011 00:30

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


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

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