Search code examples
actionscript-3flashmemory-leaksimage-loadingadobe-scout

Creating inline function after loading an image causes memory leak


I was analyzing an unexpected memory leak in our game project and found some strange results. I am profiling using Adobe Scout and eliminated all other factors like starling, texture or our loading library. I reduced the code to simply load a png and immediately allocate an empty inline function on its complete event.

Loading a png allocates image on default and if you do nothing after loading gc clears that image. But creating an inline function seems to prevent that image to be garbage collected somehow. My test code is;

public class Main extends Sprite 
{
    private var _callbacks:Array = new Array();

    public function Main() 
    {
        load("map.png", onPngLoaded);
    }

    private function onPngLoaded(bitmap:Bitmap):void 
    {
        _callbacks.push(function():void { });
    }

    public function load(url:String, onLoaded:Function):void 
    {
        var loader:Loader = new Loader;

        var completeHandler:Function = function(e:Event):void {
            loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, completeHandler);
            onLoaded(loader.content);
        }

        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);

        loader.load(new URLRequest(url));   
    }
}

If you remove the code which creates an inline function;

    private function onPngLoaded(bitmap:Bitmap):void 
    {
        // removed the code here!
    }

gc works and clears the image from memory.

Since having no logical explanation for this, I suspect of a flash / as3 bug. I will be glad to hear any comments who tests my code and gets the same results.

Note: To test, replace the main class of an empty as3 project with my code and import packages. You can load any png. I am using flashdevelop, flex-sdk 4.6.0 and flash player 14.


Solution

  • When you create an inline function, all local variables get stored with it in the global scope. So in this case, that would include the bitmap parameter.

    For more information, see this: http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f54.html

    Here is the relevant part:

    Any time a function begins execution, a number of objects and properties are created. First, a special object called an activation object is created that stores the parameters and any local variables or functions declared in the function body....Second, a scope chain is created that contains an ordered list of objects that Flash Player or Adobe AIR checks for identifier declarations. Every function that executes has a scope chain that is stored in an internal property. For a nested function, the scope chain starts with its own activation object, followed by its parent function’s activation object. The chain continues in this manner until it reaches the global object.

    This is another reason why inline/anonymous functions are best avoided in most situations.