I have an AIR app that renders images from a Flash editor. You can customize several surfaces - they all have the same width and height. Each surface is then rendered by the AIR app.
I'm struggling with a memory leak I fail to address.
For each surface I need to render, I have a Sprite containing many components (other sprites - some having event listeners, BitmapDatas and other children components, sprites, etc).
I'm already aware of BitmapData issues to be garbage collected, I tested both :
Memory leak is still happening in equal proportion.
Here is my loop :
var bm:BitmapData = new BitmapData(destDim.x, destDim.y, true, bgColor);
var mtx:Matrix = new Matrix();
trace('before drawing :'+(System.privateMemory/1024));
bm.draw(myBigSprite, mtx, null, null, null, true);
trace('after drawing :'+(System.privateMemory/1024));
var result:Bitmap = new Bitmap(bm, PixelSnapping.NEVER, true);
//return result and encode Bitmap to png
result.bitmapData.dispose();
result.bitmapData = null;
result = null;
Result :
before drawing :208364
after drawing :302816
Wrote bitmap to file: surface0.png
before drawing :303296
after drawing :446160
Wrote bitmap to file: surface1.png
before drawing :446160
after drawing :565212
Wrote bitmap to file: surface2.png
before drawing :565924
after drawing :703100
Wrote bitmap to file: surface3.png
before drawing :703572
after drawing :834420
Wrote bitmap to file: surface4.png
I feel like I'm missing something in draw function behaviour. It seems like I have newly created instances of the components of myBigSprite that persists after draw operation.
I tried to completely destroy myBigSprite at the end of each loop, it does not change anything....
Any hint would be appreciated !
Ok guys, I eventually understood and fixed this issue.
First of all, I installed and ran Adobe Scout. Excellent tool.
As you may not see (plus it's in French language), I generated 3 surfaces corresponding to the edges. The "big" green bar on the right which is mass memory consuming represent "Bitmap display objects". Interesting ! Never heard of those before.
A Google search later, I found this article : https://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e26.html
It explains
For example, in the code excerpt shown earlier, once the load operation for the pict Loader object is complete, the pict object will have one child display object, which is the bitmap, loaded. To access this bitmap display object, you can write pict.getChildAt(0).
So I began to undestand that, somehow, maybe Bitmap object are attached as children on some objects of myBigSprite
.
Finally, I created a recursive function to search and destroy all Bitmap
, BitmapData
and ByteArray
objects contained in myBigSprite
AFTER the draw
operation
//inside render function
bm.draw(myBigSprite, mtx, null, null, null, true);
destroyDisplayObjects(myBigSprite);
...
private function destroyDisplayObjects(obj):void{
if ("numChildren" in obj){
for (var i:int = 0; i<obj.numChildren; i++)
{
destroyDisplayObjects(obj.getChildAt(i));
}
}
else {
if (flash.utils.getQualifiedClassName(obj) == "flash.display::Bitmap"){
//trace ('FREE BITMAP');
obj.bitmapData.dispose();
obj.bitmapData = null;
obj = null;
return;
}
else if (flash.utils.getQualifiedClassName(obj) == "flash.display::BitmapData"){
//trace ('FREE BITMAPDATA');
obj.dispose();
obj = null;
return;
}
else if (flash.utils.getQualifiedClassName(obj) == "flash.display::ByteArray"){
//trace ('FREE BYTEARRAY');
obj.clear();
obj = null;
return;
}
return;
}
}
Et voilà, memory is 100% cleaned after the draw operation, no more leak :)