Showing posts with label Flex Case Study. Show all posts
Showing posts with label Flex Case Study. Show all posts

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;
}