gSkinner - Home

AS3: Weakly Referenced Listeners

Posted on July 7, 2006 by Grant Skinner

I will be dealing with this in the next installment of my resource management series of articles, but I thought it was important enough to warrant a quick post in the interim.

I’ve been blogging about how important resource management is going to be in ActionScript 3, and also mentioned that we have some new tools to deal with it. One of these new tools is the ability to have weakly referenced event listeners. A weak reference is one that is not counted by the Garbage Collector (ie. it is not counted in reference counting, and it is not followed for mark sweeping). This means that if the only references remaining to an object are weak, it will be available for collection on the next GC sweep.

References associated with event listeners are often forgotten by developers, which normally results in the listener never being removed from memory. This is why weakly referenced event listeners are so handy in AS3 – if you forget to remove the listener, you will not impede the Garbage Collector’s ability to collect the object.

It’s easy to use weakly referenced listeners in AS3. Just set the fifth parameter of an addEventListener call to true:

// params: eventName, listener, capturePhase, priority, useWeakReference
someObj.addEventListener("eventName",myFunct,false,0,true);

I would very strongly recommend getting in the habit of ALWAYS setting your listeners to be weakly referenced. I can’t think of any good reasons to set it to false, so I’m kind of disappointed that it wasn’t set to use weak references by default, although I understand the rationale. The one place weakly referenced listeners fall apart is in the case of anonymous functions:

addEventListener("eventName",function(evt) { ...code... },false,0,true);

In the above example, the only reference to the anonymous function I defined in-line is the weak reference from the event dispatcher. This means the next time the GC sweeps, my function will be removed, and obviously will no longer be called. This can be very confusing to debug, because the indeterminate GC will make the results seemingly random.

Using anonymous functions in this way is bad practice though (both architecturally, and because it leaves you with no way to remove the listener), so I’d still argue for weak references by default. This is a little selfish though, because I know that we are going to have problems in the future with third party content creating strongly referenced stage listeners (and thus never being garbage collected), whereas my team will never encounter the anonymous function issue (unless it’s in debugging third party content).

So please (PLEASE!), get in the habit of always setting your event listeners to be weakly referenced. It’s a little bit of extra typing, but it’ll save everyone (you, your users, anyone that needs to integrate with / consume your content) a lot of headaches.

Kudos to Adobe for providing this functionality!

Follow @gskinner on Twitter for more news and views on interactive media.
46 Comments

Great post, Grant!

I'm having doubts about adding eventlisteners inline with mxml, now. The generated as doesn't use week references either even with anonymous functions. And in this case, the compiler generates a class member to invoke instead of using the anonymous function.

I understand that it was a late arrival to the api, so maybe Adobe refine it more for 2.1?

Posted by: James Lyon on Jul 7, 2006 11:40am

James,

I've done some investigation on the Flex framework, and there definitely seems to be room for improvement from a memory management standpoint. The framework really doesn't do much (any?) active memory management, and it probably should. It's less of an issue in Flex than with Flash for the reasons stated in my last post, but I'd love to see some improvements to it.

Cheers.

Posted by: Grant Skinner on Jul 7, 2006 12:02pm URL: http://gskinner.com/

I've download your tests file and just run it with setting weak reference to true and... events are always dispatched. I don't understand why ?

I've also tryed to evaluate GC work by tracing FP memory all along execution. I haven't notice any action of the GC while creating objects in an enterFrame handler. I don't see any change in the memory except a small increase every 5s.

For information I trying to build a pseudo "Box Model" in order to create UI components. Then that side of conception is really a big part in the project and, as you notice in your lasts posts, the new graphic structure offer a great flexibility but also great responsabilities in ressources management, especially when you have to deal with large OO structure, where objets are frequently duplicated (to provide a css like skin management with inheritance and also an object level access).

Posted by: Cédric Néhémie on Jul 7, 2006 4:44pm URL: http://book.abe.free.fr

So the Flash Player truely supports week refs. The Dictionary class can also hold items by week ref. But is it possible to create week refs to objects manually like we do in C#?

Posted by: Arrix on Jul 7, 2006 9:20pm URL: http://anotherblog.spaces.msn.com

Arrix,

Not natively, no. In my next article I will be looking at ways to circumvent this, including source code.

Posted by: Grant Skinner on Jul 7, 2006 10:10pm URL: http://gskinner.com/

Hi Grant,

Thanks so much for the series on resource management. This is a really important topic that is all too easy for developers to ignore. Just one thing... I have never heard mark-and-sweep called mark sweeping... seems like a malapropism. Thanks for your awesome articles!

Posted by: anonymous on Jul 7, 2006 10:20pm

You could be right... mark-sweep is a common term, stretching back to at least the early nineties, but I apparently decided to turn it into a verb. I'll go back and revise my terminology tomorrow. :)

Posted by: Grant Skinner on Jul 8, 2006 2:05am URL: http://gskinner.com/

Hello Grant!

I'm developing a management aplication...The whole application is based on popups and I've noticed that when I open a popup a certain memory is being used..I close the popup and guess what...the memory is not given back...

I quess that the solution would be to set a weak reference. I've tried, but i didn't manage to do that...please help!!!!!!!!!!!!!

the example could be found here: http://adidre.go.ro/popup/erw.swf

Posted by: Adu tt on Feb 19, 2007 7:11am URL: http://adidre.go.ro/popup/erw.swf

Hi Grant,

To clarify something. My understanding of automatically bound methods is that they are a bit like anonymous functions, and so if you have a class Bar with a method Bar.foo which handles events:

// from within Bar

someObj.addEventListener("eventName",foo,false,0,true);

the bound method foo will be garbage collected if you don't save a reference to it in your class like this:

this.listener = methodFoo; // save for later

someObj.addEventListener("eventName",listener,false,0,true);

Is this correct?

Posted by: Bernard Sumption on May 10, 2007 3:26am URL: http://berniecode.com

Oops, 'methodFoo' should be just 'foo' in the above obviously.

Posted by: Bernard Sumption on May 10, 2007 3:31am URL: http://berniecode.com

Hi Grant, thanks for these articles although I don't understand the rationale for not making weak references default to true. If they fall apart on anonymous functions, simply set weak references to false when using anonymous functions. Or am i missing something more?

We need as much rails methodology in the design of APIs as possible to increase fun and productivity in development. (i.e. no more attachMovie is a godsend!)

Posted by: Peter O'Brien on Jun 30, 2007 6:41am

hello, I've been tracking this memory issue and found your articles, very interesting indeed I didn't knew about the weak references.

I want to add an example of meaningful annonymous functions as event listeners, they can be used to allow the listener function to receive more parameters, they act as a wrapper that calls the real listener function with the rest of the data because inline functions inherit it's environment so we can do something like this (Flex example):

Posted by: Samus_ on Nov 7, 2007 6:53pm URL: http://web2samus.awardspace.com/

Do Loader objects with event listeners attached (eg Event.COMPLETE) persist as long as the load operation is underway? I have code that initializes a Loader within a function with the onComplete listener function nested within that function and it has never failed, but some advise that this practice is risky. I seem to remember AS2's load functions working the same way as my AS3 example above seems to be working-- that they do persist until the loader's listener event is executed.

Posted by: dster on Dec 2, 2007 8:06am

Hi Grant!

Thanks for the these articles on resource management. I just wanna clarify the situation below.

// in some class member

var foo:Function = function(e:Event):void

{

trace("foo called");

}

var urlLoader:URLLoader = new URLLoader();

urlLoader.addEventListener(Event.COMPLETE, foo, false, 0, true);

urlLoader.load(//something);

I tried this and some case the complete was never called. So is this same as the anonymous function?

I know this might not be a best practice.

Posted by: gen on Feb 5, 2008 2:23am

In my experience, setting the week reference to true is not really helping, because the instance of my object is garbage collected at an unknown time in future. Could be in a second or few minutes. Until then my object in memory will still be listening to events, which i dont want to happen. I have to unregister the listeners explicitely before setting the object referenct to null.

There is no easy way to do this either, i have know to what events a particular object is listening to, in order to unregister. I cannot get all the listeners registered by an object, there is no API to do that.

Posted by: Sri on Apr 9, 2008 6:59am

Somehow, setting the weak references to "true" actually causes more bug than it fixes for me. I've already gotten into the habit of removing the eventListener when I don't need them. In the case of an EventListener that is regularly added and removed, setting the weak references to "true" randomly prevents the EventListener to being added back at a later time. I don't understand why, but with with weak references to false (default), this does not happen. What is happening?

Posted by: Kevin on Jun 24, 2008 2:38pm URL: http://gamesandmen.blogspot.com

Hi Grant,

I can understand the rationale for this, but doesn't saying "It's also an example of bad practice because it doesn't use weak references for the listener" (one of your comments on http://www.gskinner.com/blog/archives/2008/07/additional_info.html) take it a little bit to far? I mean we have tons of references, which all needs to be cleaned up nicely in order to make garbage collection possible, and removing listeners you added is just one of those? Or am I missing something here. If I was reading someone elses code and not seeing listeners cleaned up, I'd get nervous, since then I would have to check each addListener to see if the references were weak.

Posted by: Sorv on Jul 16, 2008 12:29am URL: http://blog.objectpainters.com

Sorv,

I definitely think developers should explicitly clear their listeners, but it's something that is very frequently missed, even by the best AS developers. Always using weakly referenced listeners is a good way to ensure that if you do miss cleaning one up, it isn't going to prevent collection.

Think of it as turning on the alarm and locking your doors - it provides an added level of security.

Posted by: Grant Skinner on Jul 16, 2008 8:28am URL: http://gskinner.com/blog/

Loader objects and NetConnections do not receive event listener calls if you set useWeakReference to "true." I've encountered this problem multiple times. What do you think Adobe's thought behind this may be?

- TK

Posted by: TK on Aug 29, 2008 11:28am

I've write a little EventManager to clean all event associate to an object (a whole swf can be this object), it's a little bit ugly right now, but does it make sens ? :

Class :

package

{

import com.utils.*;

import game.*;

public class EventManager

{

private static const DEBUG = false;

private static var events:EventsHolder = null;

public function EventManager()

{

}

public static function Add(s, o, e, f) // swf, object, event, function

{

if(DEBUG)

{

trace("s", s);

trace("o", o);

trace("e", e);

trace("f", f);

}

if(!events) events = new EventsHolder();

var ed:EventDescriptor = new EventDescriptor();

if(!events[s]) events[s] = new Array();

ed.object = o;

ed.event = e;

ed._function = f;

events[s].push(ed)

o.addEventListener(e, f, false, 0, true);

}

public static function Remove(o, e, f)

{

o.removeEventListener(e, f);

}

public static function RemoveAllForSwf(s)

{

if(!events[s]) return;

while(events[s].length)

{

var e:EventDescriptor = events[s].pop();

if(e.object.hasEventListener(e.event)) e.object.removeEventListener(e.event, e._function);

}

}

}

}

internal dynamic class GameData

{

public function GameData()

{

}

}

internal dynamic class EventsHolder

{

public function EventsHolder()

{

}

}

internal dynamic class EventDescriptor

{

public function EventDescriptor()

{

}

}

How To Use :

public function ClassXXX()

{

DataManager.Instance();

EventManager.Add(this.name, this, Event.REMOVED_FROM_STAGE, onRemovedFromStage);

EventManager.Add(this.name, this, Event.ADDED_TO_STAGE, onAddedToStage);

}

private function onRemovedFromStage(e:Event)

{

EventManager.RemoveAllForSwf(this.name);

}

private function onAddedToStage(e:Event)

{

}

Posted by: Rompelstilchen on Sep 10, 2008 2:53pm

if you set the weak reference to true, do you still need to remove the event listener, or it is not necessary any more?

Thanks in advance for your reply.

Posted by: Jaime on Sep 21, 2008 6:25am

Jaime it shouldn't be necessary to remove the event listener yourself in case of a weak reference BUT there seems to be a bug in Flash Player 9. It should have been fixed in FP10 according to Ted Patrick (see comments @ http://www.onflex.org/ted/2008/09/useweakreferencesboolean-false.php) but I have the impression that the problem is still there...

Posted by: Tom Van den Eynde on Sep 24, 2008 3:39am URL: http://www.vdeprojects.com

I understand about cleaning up after yourself.. But, if i was creating a video application and i needed the to know when events were fired at any time during the playback shouldnt the event listeners always be there? or should i set the weakref to true?

Hope this makes since..?

mitch

Posted by: mitchell on Oct 6, 2008 4:00pm

I came to your article cause I had a serious memory problem in one of my projects ...

I read your article, I followed the advice and then .... my problem were gone ...

Weak Reference ! ... so simple and usefull ...

I searched in all my file for every single addEventListener and added the precious fifth argument ("true") ... waouuuh ! GREAT !!

If a could send you a beer by Email ... I would ...

Thanks A LOT !

Nicolas

Posted by: Nicolas Guionnet on Oct 31, 2008 12:46pm

Well, I wrote the last coment in a state of total enthousiasm. When I went back to my project, I noticed that some of the eventListeners were unable to triger since I had set the useWeakReference property to true. Seting it back to false solved this problems !

I have now no way to solve this ...

I decided to remove all of them manually in a 'dispose' method. (It's a lot of boring work !)

I'm sad thad what I thought was a good and light solution to the problem has indeed its drawback...

Any Idea ?

Posted by: Nicolas Guionnet on Nov 1, 2008 4:11am

Grant,

I've always used this technique when attaching listeners. However, recently after I removed a sprite with over, out, and release listeners attached, the out listener kept firing after the symbol had been removed from the stage. The only solution I've seen to force the weak reference argument to always function properly is to set the reference of the movieclip to null (this invokes garbage collection perhaps?). I am working on researching this more as I would love to have to not worry about doing anything except for setting this argument to to true.

At the moment from what I've read the only 100% stable solution would be to code a function that gets called after the symbol is removed from the stage, using the REMOVED_FROM_STAGE event, then to loop through all the symbol's listeners and remove them. Not sure if this is possible yet though...

Any insight into the matter would be much appreciated.

Many thanks & Happy Holidays,

Julian

Posted by: Julian on Dec 16, 2008 3:15pm URL: http://www.julianrwilson.com

From this article:

"A weak reference is one that is not counted by the Garbage Collector (ie. it is not counted in reference counting, and it is not followed for mark sweeping). This means that if the only references remaining to an object are weak, it will be available for collection on the next GC sweep. "

So I assume it is NOT(!!) a good practice to use weak referenced listeners since they will be removed with the next garbage collection cycle (which could also be in the next millisecond -you never know!)

Is this right?

Posted by: Mike on Dec 28, 2008 8:41am

Mike - from the article: "So please (PLEASE!), get in the habit of always setting your event listeners to be weakly referenced."

The rationale is explained in the article. Let me know if you have specific questions.

Posted by: Grant Skinner on Dec 28, 2008 9:46am URL: http://gskinner.com/blog/

I'm having trouble fixing an issue with a gotoandlearn tutorial that involves a video playing within a MovieClip that is spun in 3D.

http://theflashblog.com/flash/3dflip.html

http://www.gotoandlearn.com/play?id=91

At least 1 other person within the comments is having the same problem, where after the movie is spun back, the controls for the scrubber no longer respond. I'm spinning my own Movieclip and am experiencing the same loss of event listeners. Could this be an issue of event listeners being garbage collected? I'm just now trying to understand this topic. Thanks

Jim

Posted by: Jim on Jan 21, 2009 1:58pm

i don't understand why you set your event to weak if you can remove it with removeEventListener.

can anyone show me how weakListener works. i don't really catch the concept.

tqvm

Posted by: sam on Feb 20, 2009 12:49am

As I understand it, by default if an object has an Event Listener it will not be removed from memory, this means if you forget to remove a listener, the Object will still exist in memory (even if it's been removed and set to null).

By using a weak listener you change the default behaviour: the listener will not prevent the object from getting removed from memory.

Posted by: Shaw on Mar 2, 2009 9:44am

From the Adobe docs:

Class-level member functions are not subject to garbage collection, so you can set useWeakReference to true for class-level member functions without subjecting them to garbage collection.

If you set useWeakReference to true for a listener that is a nested inner function, the function will be garbage-collected and no longer persistent. If you create references to the inner function (save it in another variable) then it is not garbage-collected and stays persistent.

Posted by: Ncu on Mar 23, 2009 7:01am URL: http://www.avchat.net

Do you regret this post? You had good intentions, but we're ALL humans and will chatter! I think the post from the Adobe Doc clarified everything.

Good work Grant. I'm a personal fan!

Posted by: Chayz on Apr 3, 2009 1:22am

In a class I used:

attractTimer = new Timer(1000);

attractTimer.addEventListener(TimerEvent.TIMER, checkAttract, false, 0, true);

attractTimer.start();

Using weak reference here prevents checkAttract() from ever being called. Took me a while to find this, as I've been using weak ref for a while.

A simple:

attractTimer.addEventListener(TimerEvent.TIMER, checkAttract);

Works as expected.

?

Posted by: Dave on May 5, 2009 10:03am URL: http://www.offroadfire.com

@Dave

When using weak references, if the attractTimer variable is declared within your function, then when the function completes and the variable goes out of scope, there will no longer be any references to attractTimer, and it will (eventually) be garbage collected.

By not using a weak reference, EventDispatcher still has a reference to attractTimer, and thus it will not be collected when the function completes.

A solution is to declare an instance variable that holds a reference to attractTimer and use weak references. Then clean up the variables and event listeners when they are no longer needed.

You dont show all of the code, but this could be what is causing your issue.

mike chambers

mesh@adobe.com

Posted by: mike chambers on Jun 19, 2009 2:36am URL: http://www.mikechambers.com

I got in the habit of always using weak references and then (painfully) learned to be more careful. If the only reference to the object that added the listener was in a local variable that goes out of scope, the listeners disappear immediately. This is to be expected but it isn't always obvious. In such cases, you must either use strong references or make sure that there's at least one reference to your object when the event occurs. Local variables usually go out of scope before your event arrives, but an instance variable should work (unless your instance is collected).

Posted by: Larry Emlich on Jun 24, 2009 10:56am

Hi Grant!

I never use weak references, because I think it's not a good programming-style. I also think that this may cause some strange errors when a needed listener is removed. Instead of this I wrote a ListenerProxy-Class that keeps track of the listeners registered on an object. You can also simply add/remove multiple listeners on multiple objects. You may have a look at my website and try it out.

Regards,

Daniel

Posted by: Daniel Bunte on Jul 6, 2009 5:06am URL: http://danielbunte.de

Hello!

Thanks for this lesson (but especially for the info about the GC I thank you..).

A quick question: When we dispatch events, I understand the Event object references a 'target' and a 'currentTarget'.

Are those references weak or strong?

Bye, Oli.

Posted by: Oliver on Jul 29, 2009 11:14am

Oliver - those are strong, but they are also transient (ie. they only exist while the event is being dispatched), unless you hold a reference to the event (which would be unusual).

Posted by: Grant Skinner on Jul 29, 2009 11:23am URL: http://gskinner.com/blog/

Keep it coming Mr Skinner very useful indeed.

Posted by: Josh Noble on Sep 3, 2009 8:38am URL: http://www.visualdialects.co.uk

From the Flash Help:

useWeakReference:Boolean (default = false) — Determines whether the reference to the listener is strong or weak. A strong reference (the default) prevents your listener from being garbage-collected. A weak reference does not.

It's the opposite of what your saying. Or am I missing something?

Posted by: Chris on Jan 6, 2010 2:25am

just dont use anonymous functions. i was using them till i had big trouble with the remove.

your code will look much better if you dont use. just put a global param:Object into your class. then you can call anything when the event dispatches e.g e.target.param.callback(e.target.param.data).

Posted by: peter on Mar 5, 2010 5:24am

So I posted this on my site (below) however i figured it might be useful here. It's for removing an anon function:

Hey guys and gals, quick lesson in flex. One popular thing to do is use something called an anonymous function with eventListeners when you want to pass the function something more than just the event. You would typically just say:

myObj.addEventListener(Event.ENTER_FRAME, function(a_event:Event):void{someotherFunc(a_event, additionalArgs);});

But this sucks if you are going to want to remove the listener. So something you can do is the following. You can create a function variable (func), then set the anonymous function to this var. Then the second function that you ultimately want to call (func2) will have an optional parameter ‘myHackFunc’ that will be the variable that you created (func). Then you just call remove event listener on ‘myHackFunc’.

I have heard of other ways of doing this, mainly, using ‘arguments.callee’ This causes my app to die, but the way described above, and shown below, seems to work all the time. Hope it helps!

public function myFunc1():void{

var func:Function = function(a:Event):void{ func2 (a, some_args, func)};

i.addEventListener(Event.ENTER_FRAME, func);

}

public function func2(a_event:Event, some_args:*, myHackFunc:Function = null):void{

a_event.currentTarget.removeEventListener(Event.ENTER_FRAME, myHackFunc);

}

You can read the whole thing here: http://constipatedkoala.andrewluly.com/2009/04/removing-anonymous-function-from-event.html

Posted by: Andrew on Aug 11, 2010 6:25pm URL: http://www.constipatedkoala.com

Oliver - those are strong, but they are also transient (ie. they only exist while the event is being dispatched), unless you hold a reference to the event (which would be unusual).

Posted by: altin çilek form seti on Jan 26, 2011 9:42am URL: http://www.altincilekformseti.tk

Great post! Still relevant.

Posted by: Kawika on Jun 3, 2011 3:10pm URL: http://www.heftelstudios.com

I prefer weak refs myself, but can think of at least one situation where a strong ref helps implement good design. It's something I call 'translate event', it raises the semantic level of a view event like this:

static public function translateEvent(type:String, newEvent:Event, target:DisplayObject):void {
target.addEventListener(type, function(e:Event):void {
target.dispatchEvent(newEvent);
});
}

Used like so:
translateEvent(MouseEvent.CLICK, MyViewEvent.PLAY_GAME, thePlayButton);

In these cases I never want to remove the listener for the lifecycle of the button. I always want to hear PLAY_GAME not just CLICK. Strong ref helps implement this in a simple way.

Note: as3 EventDispatcher.dispatchEvent clones the event. So if doing something like this, implement clone on event subclasses that define their own properties.

Posted by: John on Apr 27, 2013 11:58am