Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AS3 Memory Leak Example

Can someone post an example of as3 code (specifically event listener included) that would be a simple example of something that could leak memory... also hopefully could you post a solution to the problem shown?

The question is: What is a simple example of leaking memory in an AS3 event listener and how can you solve it?

like image 903
Skawful Avatar asked Apr 09 '10 16:04

Skawful


2 Answers

public class MySprite extends Sprite {

    public function MySprite() {
        if(stage) {
            init();
        } else {
            addEventListener(Event.ADDED_TO_STAGE,init);
        }
    } 

    private function init(e:Event = null):void {
        stage.addEventListener(Event.RESIZE,handleStageResize);
    }

    private function handleStageResize(e:Event):void {
        //  do some processing here.
    }

}

Somewhere else:

var mySprite:MySprite = new MySprite();
someHolder.addChild(mySprite);

Now, if at some later point you remove mySprite, it'll still hang around in memory, because it has added itself (or a reference to itself) to the stage in the init() method.

In this scenario, the best way to avoid this could be removing the listener added to the stage when mySprite is removed from the display list.

    private function init(e:Event = null):void {
        addEventListener(Event.REMOVED_FROM_STAGE,cleanUp);
        stage.addEventListener(Event.RESIZE,handleStageResize);

    }

    private function cleanUp(e:Event):void {
       stage.removeEventListener(Event.RESIZE,handleStageResize); 
    }

I'm sure other people will tell you to use weak references when adding the listener to the stage, but you should remove your listeners anyway. If you don't, when you remove mySprite from the display list and have no other refs to it, will be eligible for GC and will eventually be wiped away from memory. But until that happens, the code in handleStageResize() will continue to execute.

like image 114
Juan Pablo Califano Avatar answered Nov 20 '22 17:11

Juan Pablo Califano


I'll just follow up @Juan's answer - GC needs to be considered from the ground up as a critical aspect of application design. If you create an object, you must be aware of each reference to it, and remove each reference and nullify it to flag properly@. If you reference that object in array, that counts, if you reference it in a listener, that counts, if you reference it via a local variable, that counts too (though only during the life of the function), if its simply in the display list, that definitely counts, and on and on.

I go so far as to write my remove listener statements prior to adding them just to make sure.

I will almost always write a public destroy() method for any object to handle inner object hierarchies (parent calls destroy on child, which, in turn calls destroy on any children etc etc). Just removing / nulling a parent without doing so to each child is poor GC management.

And if you actually have any concerns that mem leak has sprung, trace out System.totalMemory just to make sure:

var mem:String = Number( System.totalMemory / 1024 / 1024 ).toFixed( 2 ) + ‘Mb’;
trace( mem ); // eg traces “24.94Mb”

Mostly - just be methodical about it - its not rocket science, but you have to be careful.

Cheers -

@ and even if you do, flash makes up its own mind about when to actually do a sweep. The best we can to is ensure an object is properly flagged and trust that it will be dealt with efficiently.

like image 4
Bosworth99 Avatar answered Nov 20 '22 15:11

Bosworth99