Friday, October 12, 2007

Memory Leak in Flex

Here comes my first case study: Memory leak by using Bitmap & BitmapData.

Currently I cope with a project which need to load external JPEGs into Flex and forming BitmapData objects. I will do some operations on the BitmapData, then put it into the Application.

During the application runtime, I will remove those bitmap display objects, but I discover the garbage collection doesn't really release memory from the application, so there is a memory leak. (The memory used up to 350M after I afk 30mins)

I study gskinner's
AS3: Resource Management pt 2, and carry out some test as following:

private function onBitmapLoadComplete(event:Event):void
{
var bitmapDataProxy:BitmapDataProxy = event.currentTarget as BitmapDataProxy;
bitmapDataProxy.removeEventListener(BitmapDataProxy.LOAD_COMPLETE, onBitmapLoadComplete);

var bitmap:Bitmap = new Bitmap(bitmapDataProxy.result.clone(), "auto", true);

var bitmapContainer:UIComponent = new UIComponent();
bitmapContainer.addEventListener(MouseEvent.CLICK, onMouseClick, false, 0, true);
bitmapContainer.addChild(bitmap);
this.addChild(bitmapContainer);

bitmapDataProxy.destroy();
bitmapDataProxy = null;
bitmap = null;
bitmapContainer = null;
}

private function onMouseClick(event:MouseEvent):void
{
var bitmapContainer:UIComponent = event.currentTarget as UIComponent;
bitmapContainer.removeEventListener(MouseEvent.CLICK, onMouseClick);

bitmap.bitmapData.dispose();
this.removeChild(bitmapContainer);
bitmapContainer = null;

bitmap=null;
}

Checked with Flex Profiler, the Memory usage up to 4279k at the loading of BitmapDataProxy.
After the loading is complete, I have trashed the BitmapDataProxy after putting the BitmapData into a Bitmap. This can be observed by observed used memory dropped to 1666k after I press the garbage collection button in Profiler. However, weird stuff came...

After I clicked on the image and removing the child. The used memory doesn't further drop down. And by observing Loitering Objects, I see there are still a bitmap object and BitmapData in the memory. So probably I can't clear it.

By further test, I found that The BitmapData left in memory is referring to the property of Bitmap, i.e. Bitmap.bitmapData. I have clear it, but I need to remove the reference in order to release the counter of reference to the object in memory.

By adding the code, I further dropped the used memory to 1141k. And there are no more BitmapData instance in the memory. but there is still one Bitmap instance. so I guess the removeChild doesn't really remove all the childs in the Display List.

bitmap.bitmapData.dispose();
bitmap.bitmapData = null;


Finally I added following code to remove the unused Bitmap instance:

bitmapContainer.removeChild(bitmap);

I finally can remove all the Memory Leakage problem in this little revising practice. I think there are much more to go over my Album Project, with project coded "Houngan".

Uhmmm, at least I see hope through this practice. And wish it helps you too.

The Finalized code as following:

private function onBitmapLoadComplete(event:Event):void
{
var bitmapDataProxy:BitmapDataProxy = event.currentTarget as BitmapDataProxy;
bitmapDataProxy.removeEventListener(BitmapDataProxy.LOAD_COMPLETE, onBitmapLoadComplete);

var bitmap:Bitmap = new Bitmap(null, "auto", true);
bitmap.bitmapData = bitmapDataProxy.result.clone();

var bitmapContainer:UIComponent = new UIComponent();
bitmapContainer.addEventListener(MouseEvent.CLICK, onMouseClick);//, false, 0, true);
bitmapContainer.addChild(bitmap);
this.addChild(bitmapContainer);

bitmapDataProxy.destroy();
bitmapDataProxy = null;
bitmap = null;
bitmapContainer = null;
}

private function onMouseClick(event:MouseEvent):void
{
var bitmapContainer:UIComponent = event.currentTarget as UIComponent;
bitmapContainer.removeEventListener(MouseEvent.CLICK, onMouseClick);

var bitmap:Bitmap = bitmapContainer.getChildAt(0) as Bitmap;

bitmap.bitmapData.dispose();
bitmap.bitmapData = null;

bitmapContainer.removeChild(bitmap);

this.removeChild(bitmapContainer);
bitmapContainer = null;

bitmap=null;
}

3 comments:

followr said...

Interesting test case. I'm using a Air application which goes into it's own screen save mode and loads random images. I'm also finding that after 30 - 40 mins the memory usage is crazy. Thanks for the tips, hopefully I can put them into practice in my own application.

gallypette said...

Thanks a lot! I couldnt figured what i was doing wrong.

Unknown said...

great!