I recently had the pleasure of debugging an AS3 image viewer application that was crashing after an hour. It seemed to be some kind of memory leak, so I looked for objects not being cleared up by the Flash Player’s garbage collector. I found that, even with AS3’s mark and sweep garbage collection, BitmapData objects left stranded (with no external references) still hog RAM, even when their DisplayObject is deleted.
A similar problem existed in AS2, but will be more acute in AS3 I think, because removing a child DisplayObject from a display list does not delete it (as removeMovieClip() would in AS1/2). Try the following example with your Windows Task Manager or Mac Activity Monitor running, you should see what I mean:
import flash.display.* import flash.events.* // Add a main container sprite to the stage var main:Sprite = new Sprite(); addChild(main); // Add event listeners for mouse move and click stage.addEventListener(MouseEvent.MOUSE_MOVE, paint); stage.addEventListener(MouseEvent.CLICK, cleanup); // Draws bitmap noise at the mouse cursor function paint (e:MouseEvent):void { var b = new BitmapData(100,100,false,0xff0000); b.noise(int(Math.random()*int.MAX_VALUE)); var bmp = new Bitmap(b); var spr = new Sprite(); spr.x = e.stageX; spr.y = e.stageY; spr.addChild(bmp); main.addChild(spr); } // Removes all of main's children from the display list function cleanup (e:MouseEvent):void { while (main.numChildren>0) { main.removeChildAt(0); } }
Once the cleanup function runs, all of main’s sprites are removed from the display list, with no more references to them – so the garbage collector should clean things up. But it won’t dispose of the BitmapData objects automatically, so you eventually run out of RAM! This problem of memory hogging occurs even if you keep references to all the clips (in an array for example) and set them to null after removing them from the display hierarchy.
I can see a lot of problems occurring as developers move to AS3 without a firm understanding of how garbage collection works. One answer would be to manually dispose of BitmapData objects or handle the REMOVED_FROM_STAGE event and perform a cleanup as necessary. Here’s quick and dirty fix that cures the memory leak:
function cleanup (e:MouseEvent):void { while (main.numChildren>0) { main.getChildAt(0).getChildAt(0).bitmapData.dispose(); main.removeChildAt(0); } }