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

Psycho Tiger 29.01.2011 00:50

С тех пор как мы ловили RTE в релизной версии плеера, потому что в дебаговой этого RTE не было — я отношусь к версиям FP очень внимательно.

VitaliyKrivtsov 29.01.2011 01:23

Если не вызвать принудительно GC, и подождать немножко пока сам запустится, то получим:
loader удаляется если описаны от всех слушателей и e.target.loader.content не находится в списке отображения;
e.target.loader.content не находится в списке и без ссылки - тоже удаляется;
loader удаляется, если на e.target.loader.content есть ссылка, не находится в списке отображения, обнулен;

не удаляется loader, если не отписаться от слушателей;
не удаляется loader, если на e.target.loader.content была ссылка за пределами функции,
не удаляется loader, если e.target.loader.content находится в списке отображения но нет ссылки за пределами функции,


вот так все печально.

Psycho Tiger 29.01.2011 21:23

Прошу прощения, туплю =)
Цитата:

Если вместо SWF-файлов загружаются изображения (JPEG, GIF или PNG), то не требуется указывать ни домен защиты, ни домен безопасности, поскольку эти понятия имеют смысл только применительно к SWF-файлам. Необходимо принять всего одно решение: требуется ли программный доступ к растровому представлению загруженного изображения? Если да, см. свойство checkPolicyFile.
Обещаю больше думать и меньше пить.

dimarik 31.01.2011 13:17

Всем привет! Пару дней сидел без интернета.

Цитата:

Сообщение от VitaliyKrivtsov (Сообщение 968709)
Если не вызвать принудительно GC, и подождать немножко пока сам запустится, то получим:
- loader удаляется если описаны от всех слушателей и e.target.loader.content не находится в списке отображения;

Верно только второе. Можно не отписывать loaderInfo. Второе верно только как следствие того, что опишу ниже.

Цитата:

- e.target.loader.content не находится в списке и без ссылки - тоже удаляется;
Логично.

Цитата:

- loader удаляется, если на e.target.loader.content есть ссылка, не находится в списке отображения, обнулен;
Неверно. Есть ссылка на content - Loader жив.

Цитата:

не удаляется loader, если не отписаться от слушателей;
Удаляется. Уже высказался.

Цитата:

не удаляется loader, если на e.target.loader.content была ссылка за пределами функции,
Тут я уже говорил. Если есть ссылка, неважно где: в пределах функции, метода или поля класса. Важно другое: пока она есть, значит она указывает на реальный живой объект,
Вышли мы из функции, ссылка пропала.

Цитата:

не удаляется loader, если e.target.loader.content находится в списке отображения но нет ссылки за пределами функции,
Верно. Ссылка в таком случае будет (stage._childList[N]...displayObjectContainer._childList[N] as DisplayObject).loaderInfo.loader;


Дальше расскажу что происходит с loader при загрузке растровых изображений (JPEG, PNG, GIF).

Эксперимент проводился с Adobe Flash Player 10.0 r45 debug. Результат исследований заставил задуматься.
Пока существует ссылка на BitmapData контента (loader.content as Bitmap).bitmapData, (loaderInfo.content as Bitmap).bitmapData, жив и лоадер.
Можно даже сделать ей dispose(), ничего не изменится. Скажу больше. Даже bitmapData.clone() не позволит удалиться лоадеру.

Однако после bitmapData.draw() GC может удалить Loader.

Код маленького эксперимента
Код AS3:

///////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2011. Dimarik
//
///////////////////////////////////////////////////////////////////////////////
 
package
{
 
        import flash.display.Bitmap;
        import flash.display.BitmapData;
        import flash.display.Loader;
        import flash.display.LoaderInfo;
        import flash.display.Sprite;
        import flash.display.StageAlign;
        import flash.display.StageScaleMode;
        import flash.events.Event;
        import flash.events.IEventDispatcher;
        import flash.net.URLRequest;
 
        /**
        *  @author                                Dimarik
        *  @version                        1.0
        *  @langversion                3.0
        *  @playerversion                9.0
        *
        */

        [SWF(width="400", height="200", frameRate="21", backgroundColor="#E0EEEE")]
 
        public class LoaderTest extends Sprite {
 
                //-------------------------------------------------------------------------
                //
                //  Constructor
                //
                //-------------------------------------------------------------------------
 
                public function LoaderTest() {
                        super();
                        super.addEventListener(Event.ADDED_TO_STAGE, this.initialize);
                }
 
                //-------------------------------------------------------------------------
                //
                //  Private methods
                //
                //-------------------------------------------------------------------------
 
                private var _bitmapData:        BitmapData;
 
                //-------------------------------------------------------------------------
                //
                //  Private methods
                //
                //-------------------------------------------------------------------------
 
                public function initialize(event:Event):void {
                        (event.target as IEventDispatcher).removeEventListener(event.type, arguments.callee);
 
                        super.stage.scaleMode = StageScaleMode.NO_SCALE;
                        super.stage.align = StageAlign.TOP_LEFT;
 
                        var url:                String = 'http://www.flasher.ru/forum/image.php?u=69797&dateline=1296252938';
                        var request:        URLRequest = new URLRequest(url);
                        var loader:                Loader = new Loader();
                        loader.load(request);
 
                        var li:                        LoaderInfo = loader.contentLoaderInfo;
                        li.addEventListener(Event.COMPLETE, this.handler_complete);
                }
 
                //-------------------------------------------------------------------------
                //
                //  Events handlers
                //
                //-------------------------------------------------------------------------
 
                /**
                * @private
                * В таком виде в методе не произойдет удаление Loader
                */

                private function handler_complete(event:Event):void {
                        var li:                        LoaderInfo = event.target as LoaderInfo;
                        var loader:                Loader = li.loader;
 
                        trace(li.contentType);
 
                        // Раскомментируйте, чтобы проверить, что отписывание не влияет на решение GC об удалении loader
                        //li.removeEventListener(Event.COMPLETE,                                        this.handler_complete);
 
                        var bitmap:                Bitmap = loader.content as Bitmap;
                        var bitmapData:        BitmapData = bitmap.bitmapData;
 
                        // Дублирование исходной BitmapData не влияет на лоадер. Он будет жить.
                        var bitmapData2: BitmapData = bitmapData.clone();
 
                        // Однако draw не обладает такой силой.
                        // Раскомментируйте, чтобы проверить, что в этом случае лоадер будет удален
                /*
                        var bitmapData2: BitmapData = new BitmapData(bitmapData.width, bitmapData.height);
                        bitmapData2.draw(bitmap);
                */

 
                        bitmap = new Bitmap(bitmapData2);
 
                        // Пока есть ссылка на bitmapData, лоадер не будет удален. Закомментируйте для удаления лоадера.
                        this._bitmapData = bitmapData2;
 
                        // Пока используется оригинальная bitmapData или раздупленная через clone() лоадер будет жить.
                        //super.addChild(bitmap);
 
                        loader.unloadAndStop();
                }
 
        }
}

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

Psycho Tiger 03.02.2011 00:47

Очень интересные выводы.
Могу сказать, что
Код AS3:

// Раскомментируйте, чтобы проверить, что отписывание не влияет на решение GC об удалении loader
//li.removeEventListener(Event.COMPLETE,                                        this.handler_complete);

в некотором роде очевидно и правильно. Например совсем недавно я немного размышлял о таинствах съест-не съест с EventDispatcher`ом. Ситуация аналогичная: мы подписали EventDispatcher, который был зануллен вместе с Loader`ом.

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

Если не секрет, как ты догадался проверить удаляется ли после draw?

Цитата:

(только не надо говорить, что изображение загружается не в аппдомен)
Этакий безымянный дефинишн? Поделись информацией, почему ты так считаешь.

VitaliyKrivtsov 03.02.2011 06:02

dimarik, я же не с потолка написал случаи когда лоадер удаляется, а когда нет.
Проводил тесты по коду из этого же топика.
Может просто нужно более подробно описать, как тот или иной тест проводился.

terbooter 03.02.2011 09:10

VitaliyKrivtsov,
вот этот пункт у меня не работает
Цитата:

loader удаляется, если на e.target.loader.content есть ссылка, не находится в списке отображения, обнулен;
Использую ваш же код, заменив обработчик
Код AS3:

                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();
 
                        this.contentLink = loader.content;
 
                        //sprite.addChild(bitmap);
                        //sprite.addEventListener(MouseEvent.CLICK, clickHandler);
 
                        //addChild(sprite);
 
                        loader.unloadAndStop(true);
                }

У меня в этом случае лоадер не удаляется

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

Что можешь посоветовать для загрузки "мимолетных" картинок, которые могут легко появится на экране и так же легко исчезнуть?
Повторно использовать тот же лоадер. Или пул лоадеров.
Чем меньше слов new (и фабричных методов) в коде тем меньше вероятность утечек=)

VitaliyKrivtsov 03.02.2011 20:03

У вас ссылка contentLink в пределах поля класса есть, ее нужно будет удалить из списка отображения а потом занулить, когда bitmap уже будет не нужен, так же желатильно отписать от слушателей loader и занулить его, и тогда - будет удален и лоадер и битмап.

dimarik 08.02.2011 23:08

В том и дело, что если для каждой картинки создавать свой лоадер, то в памяти будет висеть и растр и лоадер. Однако если грузить картинки и, вообще, ресурсы, через ограниченное число лоадеров (речь идет именно об экземплярах класса Loader), то мы бережем память на getSize(new Loader()) * numКартинок - getSize(new Loader()) * numLoaders; Чем больше картинок, тем большая экономия.

Psycho Tiger 09.02.2011 00:05

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


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

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