Flex Module 內存泄露的問題

Flex Module 內存泄露問題的解決辦法

幾種RIA技術對比,Flex的模塊化支持應該說還是比較不錯的。

可是使用ModuleLoader簡單實驗一下就會發現,每次unload, load 模塊,瀏覽器內存會不停增長。增長幅度1至若干M。

搜索了一下解決方法:

        一說使用新的spark裏的ModuleLoader,但是試了以後實際不解決問題。

        還有說在Module的CreateComplete裏將Module引用傳給 Application

Application監聽Module的unload事件,在unload時將Module destroy,但是我找了半天沒有找到有什麼destroy方法可供調用。

        怎麼辦呢,最後想到了關於Module性能提升的方法,就是緩存Module,Module建立以後進行緩存。防止反覆的新建Module對象。

經驗證本方式可以基本解決內存泄露的問題,畢竟一個系統你可以點千百次,但是一般有千百個Module的系統還是比較少,估計一般多的就幾十個

Module吧,而常用的可能就幾個。

現將ModuleLoader的擴展類貼出。當然是老外寫的,代碼中有說明作者,這裏做一轉載:

package 
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	
	import mx.events.FlexEvent;
	import mx.events.ModuleEvent;
	import mx.modules.IModuleInfo;
	import mx.modules.ModuleLoader;
	import mx.modules.ModuleManager;
	
	/**
	 * This class manages the loading, unloading and caching of Flex Modules
	 * This is a modified version of the mx.modules.ModuleLoader class
	 *
	 * @author Danny Kopping - [email protected]
	 */
	public class CachedModuleLoader extends ModuleLoader
	{
		private var map:Dictionary = new Dictionary();
		
		private var _url:String = null;
		private var module:IModuleInfo;
		private var loadRequested:Boolean = false;
		
		public function CachedModuleLoader()
		{
			super();
		}
		
		override public function set url(value:String):void
		{
			if (value == _url)
				return;
			
			if (module)
			{
				module.removeEventListener(ModuleEvent.PROGRESS, moduleProgressHandler);
				module.removeEventListener(ModuleEvent.SETUP, moduleSetupHandler);
				module.removeEventListener(ModuleEvent.READY, moduleReadyHandler);
				module.removeEventListener(ModuleEvent.ERROR, moduleErrorHandler);
				module.removeEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler);
				
				//module.release();
				module = null;
				
				if (child)
				{
					removeChild(child);
					//child = null;
				}
			}
			
			_url = value;
			
			dispatchEvent(new FlexEvent(FlexEvent.URL_CHANGED));
			removeAllChildren();
			
			if (_url != null && loadRequested)
			{
				if(!map[_url])
					loadModule();
				else
				{
					
					child = map[_url];
					addChild(child);
				}
			}
		}
		
		override public function get url():String
		{
			return _url;
		}
		
		override public function createComponentsFromDescriptors(recurse:Boolean = true):void
		{
			super.createComponentsFromDescriptors(recurse);
			
			loadRequested = true;
			loadModule();
		}
		
		override public function loadModule(url:String = null, bytes:ByteArray = null):void
		{
			if (url != null)
				_url = url;
			
			if (_url == null)
			{
				//trace("loadModule() - null url");
				return;
			}
			
			if (map[_url])
			{
				//trace("loadModule() - already created the child");
				return;
			}
			
			if (module)
			{
				//trace("loadModule() - load already initiated");
				return;
			}
			
			dispatchEvent(new FlexEvent(FlexEvent.LOADING));
			
			module = ModuleManager.getModule(_url);
			
			module.addEventListener(ModuleEvent.PROGRESS, moduleProgressHandler);
			module.addEventListener(ModuleEvent.SETUP, moduleSetupHandler);
			module.addEventListener(ModuleEvent.READY, moduleReadyHandler);
			module.addEventListener(ModuleEvent.ERROR, moduleErrorHandler);
			module.addEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler);
			
			module.load(applicationDomain, null, bytes);
		}
		
		override public function unloadModule():void
		{
			if (child && contains(child))
			{
				removeChild(child);
				child = null;
			}
			
			if (module)
			{
				module.removeEventListener(ModuleEvent.PROGRESS, moduleProgressHandler);
				module.removeEventListener(ModuleEvent.SETUP, moduleSetupHandler);
				module.removeEventListener(ModuleEvent.READY, moduleReadyHandler);
				module.removeEventListener(ModuleEvent.ERROR, moduleErrorHandler);
				
				module.unload();
				module.removeEventListener(ModuleEvent.UNLOAD, moduleUnloadHandler);
				module = null;
			}
			
			if(map[_url])
			{
				delete map[_url];
			}
		}
		
		private function moduleProgressHandler(event:ModuleEvent):void
		{
			dispatchEvent(event);
		}
		
		private function moduleSetupHandler(event:ModuleEvent):void
		{
			// Not ready for creation yet, but can call factory.info().
			
			dispatchEvent(event);
		}
		
		private function moduleReadyHandler(event:ModuleEvent):void
		{
			child = module.factory.create() as DisplayObject;
			dispatchEvent(event);
			
			if (child)
			{
				var p:DisplayObjectContainer = parent;
				// p.removeChild(this);
				addChild(child);
				
				map[url] = child;//ModuleManager.getModule(_url);
				//trace(map + ":" + url + ":" + map[url]);
			}
		}
		
		private function moduleErrorHandler(event:ModuleEvent):void
		{
			unloadModule();
			dispatchEvent(event);
		}
		
		private function moduleUnloadHandler(event:ModuleEvent):void
		{
			dispatchEvent(event);
		}
	}
}


 

該類繼承ModuleLoader,可直接在MXML中使用,經實驗可有效解決module內存泄露問題。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章