Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Сообщения за день
 

Вернуться   Форум Flasher.ru > Flash > Flex

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 01.11.2009, 14:20
AntonAL вне форума Посмотреть профиль Отправить личное сообщение для AntonAL Найти все сообщения от AntonAL
  № 1  
Ответить с цитированием
AntonAL

Регистрация: Oct 2009
Сообщений: 15
По умолчанию Страшная прожорливость Flex 4

Есть очень серьёзная проблема с Adobe AIR приложением.

В списке отображается ~1000 иконок, размером 32x32.
До загрузки иконок, приложение потребляет 31 Мб оперативной памяти.
После загрузки и отображения, потребляется уже 241 Мб памяти.

Код программы
Код AS3:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
                       xmlns:s="library://ns.adobe.com/flex/spark" 
                       xmlns:mx="library://ns.adobe.com/flex/halo">
    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            import flash.filesystem.File;
 
 
            //
            // 
            //
            var imagesFolder = "data";
            [Bindable] var images: ArrayCollection = new ArrayCollection;
 
 
            //
            // 
            //
            function LoadImages( )
            {
                /*
                    В этом случае, потребляется 70 Мб.
                */
                var folder: File = File.applicationDirectory.resolvePath( this.imagesFolder );
 
                /*
                    Если папка с иконками находится в другом месте, то кушается уже 250 Мб !!!
                */
                //var folder: File = File.applicationDirectory.resolvePath( "C:/temp" );
 
                if ( folder.isDirectory )
                {
                    var files: Array = folder.getDirectoryListing( );
                    for each( var file: File in files )
                        if ( ! file.isDirectory && file.extension == "jpeg" || file.extension == "jpg" || file.extension == "png" )
                                this.images.addItem( file.url );
                }
            }
        ]]>
    </fx:Script>
 
 
    <s:VGroup width="100%" height="100%">
 
        <s:Button label="load images" click="{LoadImages()}" />
        <s:List dataProvider="{images}" width="100%" height="100%" useVirtualLayout="false">
            <s:layout>
                <s:TileLayout columnWidth="72" rowHeight="72" />
            </s:layout>
            <s:itemRenderer>
                <fx:Component>
                    <s:ItemRenderer>
                        <!--States must be included obligatory, because they are inside of List control, that needs this states-->
                        <s:states>
                            <s:State name="normal" />
                            <s:State name="hovered" />
                            <s:State name="selected" />
                        </s:states>
 
                        <mx:Image source="{data}" width="100%" height="100%" />
                    </s:ItemRenderer>
                </fx:Component>
            </s:itemRenderer>
        </s:List>
 
    </s:VGroup>
</s:WindowedApplication>
Проект с тестовыми иконками выложил на iFolder (Project -> Clean, затем - Run)

Причём, заметил такой парадокс:
Если папка с иконками находится в bin-debug, т.е. в той же папке, что и приложение, то потребляется 70 Мб.
Если папка с иконками находится в другом месте, скажем - C:/temp, то потребляется 250 Мб.
Если посчитать, сколько будут занимать данные пикселей RGBA для 1000 иконок, размером 32x32, то получим
32x32x4x1000 = 4 Мб

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

Честно говоря, такому поведению у меня объяснения пока нет...

Есть идеи, как с этим бороться ?


Последний раз редактировалось AntonAL; 01.11.2009 в 14:30.
Старый 01.11.2009, 14:28
wvxvw вне форума Посмотреть профиль Отправить личное сообщение для wvxvw Найти все сообщения от wvxvw
  № 2  
Ответить с цитированием
wvxvw
Modus ponens
 
Аватар для wvxvw

модератор форума
Регистрация: Jul 2006
Адрес: #1=(list #1#)
Сообщений: 8,049
Записей в блоге: 38
Ну а если вы все то же самое сделаете без фреймворка, результат будет такой же или нет?
__________________
Hell is the possibility of sanity

Старый 01.11.2009, 14:44
AntonAL вне форума Посмотреть профиль Отправить личное сообщение для AntonAL Найти все сообщения от AntonAL
  № 3  
Ответить с цитированием
AntonAL

Регистрация: Oct 2009
Сообщений: 15
Пока не пробовал

Добавлено через 5 часов 26 минут
Я не очень понимаю, как удалить картинку из памяти ?

У меня такой код:
Код AS3:
package
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filesystem.File;
	import flash.system.System;
 
	import mx.collections.ArrayCollection;
	import mx.controls.Image;
 
	public class ImagesLoader extends EventDispatcher
	{
		//
		//
		//
		public function ImageLoader()
		{
		}
 
 
		//
		// Methods
		//
		public function Load( path: String )
		{
			var folder: File = new File( path );
 
			if ( folder.isDirectory )
			{
				var files: Array = folder.getDirectoryListing( );
				for each( var file: File in files )
					if ( ! file.isDirectory && file.extension == "jpeg" || file.extension == "jpg" || file.extension == "png" )
					{
						var img: Image = new Image( );
						img.source = file.url;
						//_images.push( img );
						_images.addItem( img );
 
						img.addEventListener(Event.COMPLETE, onImageLoaded );
						img.load( );						
					}
			}
		}
 
		/**
		 * References
		 * 		http://blog.empiregpservices.com/pos...n-local-images
		 */
		public function Delete( )
		{
			for ( var i = 0; i < _images.length; i++ )
			{
				//var img: Image = _images.pop() as Image;
				//img.unloadAndStop( );
				_images[i].source = null;
				//_images[i].unloadAndStop( false );
			}
			_images.removeAll();
 
			System.gc();
		}
 
		function onImageLoaded( e:Event )
		{
			var img: Image = e.target as Image;			
			img.removeEventListener( Event.COMPLETE, onImageLoaded );
 
			/*			
			var bd: BitmapData = new BitmapData( img.contentWidth, img.contentHeight );
			bd.draw( img );
			var bitmap: BitmapImage = new BitmapImage( );
			bitmap.source = bd;
			_bitmapImages.addItem( bitmap );
			*/
		}
 
 
		//
		// Internal Properties
		//
		//var _images: Array = new Array;
		var _images: ArrayCollection = new ArrayCollection;
 
		//var _bitmapImages: ArrayCollection = new ArrayCollection;
	}
}
Код приложения:
Код AS3:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
					   xmlns:s="library://ns.adobe.com/flex/spark" 
					   xmlns:mx="library://ns.adobe.com/flex/halo">
	<fx:Script>
		<![CDATA[
			import flash.events.Event;
 
			import mx.collections.ArrayCollection;
			import mx.events.FlexEvent;
 
 
			var imageLoader: ImageLoader = new ImageLoader;
		]]>
	</fx:Script>
 
 
	<s:VGroup width="100%" height="100%">
		<s:HGroup>			
			<s:Button label="load images" click="{imageLoader.Load( 'C:/temp' )}" />
			<s:Button label="delete images" click="{imageLoader.Delete()}" />			
		</s:HGroup>
 
		<s:Scroller  width="100%" height="100%" >
			<s:TileGroup id="thumbnailsList" width="100%" columnWidth="72" rowHeight="72" />
		</s:Scroller>
	</s:VGroup>
</s:WindowedApplication>

В методе Delete() я перепробывал уже все мыслимые комбинации, но никак не могу заставить GarbageCollector реально удалить картинки из памяти. Иногда, один раз из 15, они удаляются - я вижу в менеджере процессов, как занимаемая память сразу падает с 250 до 30 Мб.
В некоторых статьях советуют делать img.source = "", но это не помогает.

В принципе, если добиться удаления mx.components.Image, предварительно скопировав пиксельные данные, то всё будет хорошо. Можно BitmapData запихнуть в BitmapImage и её отобразить в TileGroup или в любом другом Flex контейнере. Это у меня получилось один раз - отображалась 1000 иконок, и приложение кушало 40 Мб. Т.е. как раз 4 мб на картинки...


Последний раз редактировалось AntonAL; 01.11.2009 в 20:13.
Старый 01.11.2009, 20:44
Aloran вне форума Посмотреть профиль Отправить личное сообщение для Aloran Найти все сообщения от Aloran
  № 4  
Ответить с цитированием
Aloran

Регистрация: May 2009
Сообщений: 223
Записей в блоге: 1
Во флеше нельзя принудительно чистить мусор. Можно лишь подготовить программу к чистке. а уж будет она или нет, это нам не ведомо.

Старый 01.11.2009, 20:57
wvxvw вне форума Посмотреть профиль Отправить личное сообщение для wvxvw Найти все сообщения от wvxvw
  № 5  
Ответить с цитированием
wvxvw
Modus ponens
 
Аватар для wvxvw

модератор форума
Регистрация: Jul 2006
Адрес: #1=(list #1#)
Сообщений: 8,049
Записей в блоге: 38
В AS3 только имена классов с прописной, все остальное, за исключением констант - со строчной, константы - все прописные.
После вызова конструктора нужно писать круглые скобки.

Ну так вы опять же используете фреймворковские классы... попробуйте повторить эксперимент просто используя классы плеера. Вполне может быть, что во фреймворковских классах баг. И раз вы уже из локальной файловой системы работаете, то, наверняка логичнее было бы использовать FileStream и проследить за тем, что стрим закрывается после каждой загрузки, ну и т.д.
Если у вас получится тот же результат с просто Loader'ом + FileStream'ом, тогда, пожалуй, баг плеера, и останется только багрепорты писать, а если это фреймворк, то можно самому пофиксить.
__________________
Hell is the possibility of sanity

Старый 01.11.2009, 22:03
AntonAL вне форума Посмотреть профиль Отправить личное сообщение для AntonAL Найти все сообщения от AntonAL
  № 6  
Ответить с цитированием
AntonAL

Регистрация: Oct 2009
Сообщений: 15
Я пробовал использовать класс Loader - та же история. Жрёт 250 Мб.
Пробовал также SWFLoader - также.
Пробовал BitmapImage - тоже самое.

Попобовал использовать URLLoader - с ним немного другая история. Загруженная информация занимает в памяти ~ 5 Мб, как и должно быть. Удаление происходит прекрасно. Для массива, в котором сидят 1000 URLLoader'ов, я вызываю метод splice(), и из памяти всё удаляется. Но вот проблема - как из URLLoader'а получить картинку ? Он может грузить либо текст, либо binary ... А binary - это образ файла, а не пикселей...

Старый 01.11.2009, 23:01
wvxvw вне форума Посмотреть профиль Отправить личное сообщение для wvxvw Найти все сообщения от wvxvw
  № 7  
Ответить с цитированием
wvxvw
Modus ponens
 
Аватар для wvxvw

модератор форума
Регистрация: Jul 2006
Адрес: #1=(list #1#)
Сообщений: 8,049
Записей в блоге: 38
Ну как бы Loader и нужно было загружать, можно конечно сначала URLLoader а потом Loader.loadBytes() но это не целесообразно в виду того, что будете делать работу фактически 2 раза.
Естественно, после того как картинка распакуется, она будет больше, тут ничем не поможешь, но цифры как-то очень сильно отличаются...
А вообще, считайте так: количество пикселов * 3 байта + (точно не скажу, но, пусть будет еще по 50 байт на каждую кратинку, на свойства там всякие и т.п.) *
Сколько должно получится?

* это при условии, что после загрузки картинки вы ее тут же отрисовываете в битмапдату, удаляете, и повеху загружаете следующую. Иначе - добавьте еще и исходный размер картинки.
__________________
Hell is the possibility of sanity

Старый 02.11.2009, 12:09
AntonAL вне форума Посмотреть профиль Отправить личное сообщение для AntonAL Найти все сообщения от AntonAL
  № 8  
Ответить с цитированием
AntonAL

Регистрация: Oct 2009
Сообщений: 15
Есть!!! Я сделал это

Код загрузчика
Код AS3:
package
{
	import flash.display.Bitmap;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filesystem.File;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.system.System;
 
	import mx.controls.Image;
 
	import spark.primitives.BitmapImage;
 
	public class ImageLoader extends EventDispatcher
	{
		//
		// Construction
		//
		public function ImageLoader()
		{
		}
 
 
		//
		// Properties
		//
		public function get images( ): Array
		{	
			return _images;
		}
 
 
		//
		// Methods
		//
		public function Load( path: String )
		{
			// Enables loading mode, that consumes a huge amount of RAM
			var RAM_Hell = false;
 
			/*
				Потребляют много памяти:
					Image
					BitmapImage
					Loader
					SWFLoader
				URLLoader
					Выделенная память совпадает по размеру с той, которая необходима для хранения данных о пикселях
					Освобождается отлично
			*/
			var folder: File = new File( path );
			if ( folder.isDirectory )
			{
				var files: Array = folder.getDirectoryListing( );
				for each( var file: File in files )
					if ( ! file.isDirectory && file.extension == "jpeg" || file.extension == "jpg" || file.extension == "png" )
					{
						if ( ! RAM_Hell )
						{
							// С этим вариантом загрузки, приложение потребляет 32 мб
							var loader: URLLoader = new URLLoader( );
							loader.dataFormat = URLLoaderDataFormat.BINARY;
							loader.addEventListener(Event.COMPLETE, onLoadingComplete );
							loader.load( new URLRequest(file.url) );
						}
						else
						{
							// С таким вариантом - 250 Мб !!!
							var img: Image = new Image( );						
							img.addEventListener( Event.COMPLETE, onImageLoaded );
							img.load( file.url );
						}
					}
			}
		}
 
		/**
		 * References
		 * 		http://blog.empiregpservices.com/pos...n-local-images
		 */
		public function Delete( )
		{
			_images.splice( 0, _images.length );
 
			System.gc();
		}
 
 
		//
		// Internal logic
		//		
		function onLoadingComplete( e: Event )
		{
			var loader: Loader = new Loader( );
			loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onParsingComplete );
			loader.loadBytes( e.target.data );
		}
		function onParsingComplete( e: Event )
		{
			var img: BitmapImage = new BitmapImage( );
			img.source = (e.target.content as Bitmap).bitmapData;
			_images.push( img );
		}
 
 
		function onImageLoaded( e:Event )
		{
			var img: Image = e.target as Image;			
			img.removeEventListener( Event.COMPLETE, onImageLoaded );
 
			_images.push( img );
		}
 
 
		//
		// Internal Properties
		//
		var _images: Array = new Array;
	}
}

Код тестового приложения
Код AS3:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" 
					   xmlns:s="library://ns.adobe.com/flex/spark" 
					   xmlns:mx="library://ns.adobe.com/flex/halo">
	<fx:Script>
		<![CDATA[
			import spark.primitives.BitmapImage;
 
 
			var imageLoader: ImageLoader = new ImageLoader;
 
			function displayImages( )
			{
				for each( var img in imageLoader.images )
					this.thumbnailsList.addElement( img );
			}
		]]>
	</fx:Script>
 
 
	<s:VGroup width="100%" height="100%">
		<s:HGroup>			
			<s:Button label="load images" click="{imageLoader.Load( 'C:/temp' )}" />
			<s:Button label="delete images" click="{imageLoader.Delete()}" />
			<s:Button label="display" click="{displayImages()}" />
		</s:HGroup>
 
		<s:Scroller  width="100%" height="100%" >
			<s:TileGroup id="thumbnailsList" width="100%" columnWidth="72" rowHeight="72" />
		</s:Scroller>
	</s:VGroup>
</s:WindowedApplication>
Результат - приложение со всеми загруженными картинками занимает 32 Мб против 250 !
В коде есть флаг RAM_Hell, выставив который в true, можно пронаблюдать, как при загрузке картинок сразу откушается 250 метров

Спасибо вам за помощь


Последний раз редактировалось AntonAL; 02.11.2009 в 12:12.
Создать новую тему Ответ Часовой пояс GMT +4, время: 22:03.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


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


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