![]() |
|
||||||||||
|
|||||
|
Регистрация: Oct 2009
Сообщений: 15
|
Есть очень серьёзная проблема с Adobe AIR приложением.
В списке отображается ~1000 иконок, размером 32x32. До загрузки иконок, приложение потребляет 31 Мб оперативной памяти. После загрузки и отображения, потребляется уже 241 Мб памяти. Код программы <?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> Причём, заметил такой парадокс: Если папка с иконками находится в bin-debug, т.е. в той же папке, что и приложение, то потребляется 70 Мб. Если папка с иконками находится в другом месте, скажем - C:/temp, то потребляется 250 Мб. Если посчитать, сколько будут занимать данные пикселей RGBA для 1000 иконок, размером 32x32, то получим 32x32x4x1000 = 4 Мб useVirtualLayout мне необходимо отключить, чтобы при прокрутке, пользователь не видел, как подгружаются иконка Честно говоря, такому поведению у меня объяснения пока нет... Есть идеи, как с этим бороться ? Последний раз редактировалось AntonAL; 01.11.2009 в 14:30. |
|
|||||
|
Регистрация: Oct 2009
Сообщений: 15
|
Пока не пробовал
Добавлено через 5 часов 26 минут Я не очень понимаю, как удалить картинку из памяти ? У меня такой код: 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; } } <?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. |
|
|||||
|
Modus ponens
|
В AS3 только имена классов с прописной, все остальное, за исключением констант - со строчной, константы - все прописные.
После вызова конструктора нужно писать круглые скобки. Ну так вы опять же используете фреймворковские классы... попробуйте повторить эксперимент просто используя классы плеера. Вполне может быть, что во фреймворковских классах баг. И раз вы уже из локальной файловой системы работаете, то, наверняка логичнее было бы использовать FileStream и проследить за тем, что стрим закрывается после каждой загрузки, ну и т.д. Если у вас получится тот же результат с просто Loader'ом + FileStream'ом, тогда, пожалуй, баг плеера, и останется только багрепорты писать, а если это фреймворк, то можно самому пофиксить.
__________________
Hell is the possibility of sanity |
|
|||||
|
Регистрация: Oct 2009
Сообщений: 15
|
Я пробовал использовать класс Loader - та же история. Жрёт 250 Мб.
Пробовал также SWFLoader - также. Пробовал BitmapImage - тоже самое. Попобовал использовать URLLoader - с ним немного другая история. Загруженная информация занимает в памяти ~ 5 Мб, как и должно быть. Удаление происходит прекрасно. Для массива, в котором сидят 1000 URLLoader'ов, я вызываю метод splice(), и из памяти всё удаляется. Но вот проблема - как из URLLoader'а получить картинку ? Он может грузить либо текст, либо binary ... А binary - это образ файла, а не пикселей... |
|
|||||
|
Modus ponens
|
Ну как бы Loader и нужно было загружать, можно конечно сначала URLLoader а потом Loader.loadBytes() но это не целесообразно в виду того, что будете делать работу фактически 2 раза.
Естественно, после того как картинка распакуется, она будет больше, тут ничем не поможешь, но цифры как-то очень сильно отличаются... А вообще, считайте так: количество пикселов * 3 байта + (точно не скажу, но, пусть будет еще по 50 байт на каждую кратинку, на свойства там всякие и т.п.) * Сколько должно получится? * это при условии, что после загрузки картинки вы ее тут же отрисовываете в битмапдату, удаляете, и повеху загружаете следующую. Иначе - добавьте еще и исходный размер картинки.
__________________
Hell is the possibility of sanity |
|
|||||
|
Регистрация: Oct 2009
Сообщений: 15
|
Есть!!! Я сделал это
![]() Код загрузчика 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; } } Код тестового приложения <?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> В коде есть флаг RAM_Hell, выставив который в true, можно пронаблюдать, как при загрузке картинок сразу откушается 250 метров Спасибо вам за помощь ![]() Последний раз редактировалось AntonAL; 02.11.2009 в 12:12. |
![]() |
![]() |
Часовой пояс GMT +4, время: 22:03. |
|
|
« Предыдущая тема | Следующая тема » |
|
|