昨天遇到个内存泄露的情况。查到最后发现加载外部的一个.swf里面的倒影截的位图没清除导致的。
推测loader.unloadAndStop()虽然会关闭流,但是并不释放被加载的程序中产生的BitmapData。
切记:除了纯粹的试听对象,所加载的外部程序中有监听、回调、创建了BitmapData的,此外部程序在被unload前请自行了断。否则你再怎么gc都吃着内存。
解决方案:
这种情况,我一般让被加载的flash程序实现一个dispose方法,加载它的loader在unloadAndStop()前先try一下dispose();
外部程序在提供的dispose方法中自行了断。自行了断的步骤各不相同,需要根据自身在存活期间所作所为来有的放矢地消灭自我才行。总体来讲包括:斩断自己所相关的回调、监听,释放内存(声音关闭、视频清除、关闭网络连接、清除位图数据)。
就像这样,主文件中:
- private function closeExFlash() : void
- {
- try
- {
- (exFlashLoader.content as IDispose).dispose();
- }catch(e : *)
- {
- }
- try
- {
- exFlashLoader.unloadAndStop();
- }catch(e : *)
- {
- }
- this.visible = false;
- }
还有一种方法:
被加载的Flash自己维护。这种方法只适用于文档类直接用来放到舞台的,我并不常这样做(我很多情况下把swf作为runtime sharelib用,加载进去只是需要其中一些类)——
被加载的Flash自己监听remove_from_stage事件,该事件触发时释放自己内存,上面说的斩断自己所相关的回调、监听,释放内存(声音关闭、视频清除、关闭网络连接、清除位图数据)。同时确保主程序中没有对它的引用。
对flash的东西真是不太懂啊
我也遇到這樣的問題了,雖然使用了unloadAndStop(),但我裏面用到的位圖的數據并沒有釋放內存了。我是使用loader來加載位圖的,怎麼才能清除位图数据,因為病沒有聲音了之類的。還是直接用樓主的這個。請樓主指點下了。謝謝!!
不要依赖unloadAndStop(),要自己在所有程序里实现dispose方法,移除的时候调用一下,每个程序自己释放自己所占用的内存。
bmd是要自己去释放的,unloadAndStop不会帮你搞定。
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
class Test extends Sprite
{
private var loader:Loader;
private var targetContainer:Sprite;
private var listenersList:Array;
public function Test(flieUrl:String,targetContainer:Sprite)
{
//初始化數組
listenersList = new Array();
//偵聽刪除事件
addEventListener (Event.REMOVED,remove);
this.targetContainer = targetContainer;
loader=new Loader();
//var variables:URLLoader = new URLLoader();
//variables.dataFormat = URLLoaderDataFormat.BINARY;
//variables.addEventListener (Event.COMPLETE,loadComplet);
loader.contentLoaderInfo.addEventListener (Event.COMPLETE,loadComplet);
loader.contentLoaderInfo.addEventListener (IOErrorEvent.IO_ERROR,ioErrorHandler);
loader.load (new URLRequest(flieUrl));
}
private function loadComplet(evt:Event)
{
addChild(loader);
//var content:ByteArray = evt.target.data as ByteArray;
//loader.loadBytes(content);
this.targetContainer.addChild(this);
loader.contentLoaderInfo.removeEventListener (Event.COMPLETE,loadComplet);
}
private function ioErrorHandler(evt:IOErrorEvent)
{
var bg = new BG();
addChild(bg);
this.targetContainer.addChild(this);
/*this.graphics.clear();
this.graphics.beginFill(0x000000,1);
this.graphics.lineStyle(1,0×000000,0);
this.graphics.drawRect(0,0,this.stage.stageWidth,this.stage.stageHeight);
this.graphics.endFill();
*/
loader.contentLoaderInfo.removeEventListener (IOErrorEvent.IO_ERROR,ioErrorHandler);
}
//自我毀滅的方法
private function remove (e:Event):void
{
this.targetContainer=null;
if (e.currentTarget != e.target)
{
return;
}
//刪除子對象
//trace (“刪除前所有子對象”,numChildren);
while (numChildren > 0)
{
removeChildAt (0);
}
//trace (“刪除后所有子對象”,numChildren);
//刪除偵聽
for (var i:uint=0; i<listenersList.length; i++)
{
//trace ("刪除Listener",lis[i][0]);
removeEventListener (listenersList[i][0],listenersList[i][1],listenersList[i][2]);
}
listenersList = null;
(loader.content as Bitmap).bitmapData.dispose();
loader.unloadAndStop();
loader = null;
}
}
多謝炸彈的回覆,在remove這個裏面我也做了(loader.content as Bitmap).bitmapData.dispose();這樣的動作。按道理應該是釋放掉位圖的內存的。我發現現在這樣處理了比內存不這樣處理的情況下增加的小了,每次刪除Test這個對象的實例后在新建一個再load新的圖的時候,內存的佔有就會增加。說明我上次的位圖的部份內存還是沒有清除掉了。如果我使用flash裏面畫的純色背景的話,內存就不會上漲了,所以我判斷畫你是load進來的位圖的內存沒有清掉了。但是除了上面的方法,我實在不知道還有什麽方法了。
再有你是上面code中exFlashLoader.content as IDispose在as中就沒有IDispose這個東西,所以我就用了(loader.content as Bitmap).bitmapData.dispose();不知道是不是這個上面有點出入。請炸彈幫我看下了。謝謝!!
ps:來這我發現一些實實在在的東西,學習了。
@qweasz, loader.content as Bitmap,问题是往往我们加载来的loader.content不是BMP的,那种你这样就不适用了。
IDispose是我自己的接口,只要是被加载到别的程序中的程序,都必须实现此接口,也就是都提供dispose()方法,在此方法中释放自己的内存。
比如对应你的情况,你应该把要加载的文件(flieUrl的目标)实现IDispose接口,如果你加载的是别人的文件,那就没办法了。
@鼠标炸弹,
是啊,我加載的是JPG的,那這樣加沒有辦法釋放內存了嗎?用的是lite4,好加載進去的jpg也會轉化為bmp的。因為按照jpg的大小來看只有100多kb,但加載一張圖所使用的內存進去后確實jpg另存為bmp的大小。使用這個后比原來不使用內存增加要少了,但與相比較用純色矢量背景來說(這個內存不會增長)還是有什麽東西沒有卸載掉了。
@qweasz, 加载jpg的话应该不存在这个问题啊,你要是找到问题的原因,一定要指点指点我们哦。
loader還有什麽資源,向我現在已經清楚掉了位圖的資源,但還是有些東西在殘留。因為只加載矢量圖的話確實沒有變化內存。問題還是loader的問題了。
@qweasz,
最後發現是跟播放器有關係,釋放bitmapData內存的方法沒有錯了。
感谢qweasz的指教.