Weak vs Strong References in AS3

by

For those of you not familiar with the concept, a weak-reference is a reference to an object that will not hold the linked object in memory when that object is garbage collected.

There are only two ways to create a weak reference in AS3. The first is with the IEventDispatcher.addEventListener() method which allows you to create a weak link between the dispatcher and the listener. To quote the AS3 Bible:

ActionScript 3.0 introduces the concept of weak and strong memory references. Normally, an object will be garbage collected if there are no references to the object. That is, when no objects are using a variable, it gets thrown out. Weak references allow you to reference an object but the object will still be eligible for garbage collection unless another object holds a strong reference to the object. By setting the [addEventListener() method's] useWeakReference flag to true, you will create a weak link between the event broadcaster and the event listener. That way, if an dispatcher is deleted while there are still listeners attached, the weak reference will allow it to be garbage collected. This helps to prevent memory leaks.

The other way is with the objects used as keys in a Dictionary object.

ActionScript, unlike many other languages, does not have a way to explicitly remove an object from memory. Instead it waits until all references to an object are removed and then auto-deletes it. Therefore, an object will continue to stay in memory if all strong references aren’t removed.

Below is an example of how strong-references hold an object in memory. If you’d like to try this out, copy the below text into a file called StrongReferencesExample.as

package {
	import flash.display.Sprite;

	public class StrongReferencesExample extends Sprite {
		public function StrongReferencesExample() {
			// create a new object called dog. Add it to the first leash object
			// and make leash2 a copy of leash 1.
			var leash1:Object = new Dog();
			var leash2:Object = leash1;

			// tracing both leashes will show that they hold a reference to the Dog
			trace(leash1); // [object Dog]
			trace(leash2); // [object Dog]

			// deleting the dog from the first leash will not remove it from the second leash
			// even though we originally set leash2 equal to leash1
			leash1 = null;
			trace(leash1); // null
			trace(leash2); // [object Dog]

			// The object (dog) will not be free until all of the references to it (leashes) are broken.
			leash2 = null;
			trace(leash1); // null
			trace(leash2); // null
		}
	}
}
// Define a simple Dog class within the same file.
class Dog {}

Richard Lord over at Big Room Games has an interesting article on hacking AS3 to allow you to create weak-references to objects. The hack is pretty decent but lacks a few things I’d like to see like strong typing at compile-time or a more refined ‘memory manager’ type functionality. However, I tried implementing both of these and came up empty handed. If you can think of a way to make this strong-typed, I’ll give you a candy bar.

Using the WeakReference hack could be useful if you want to make sure that an object will not stay in memory if you forget to delete all references to it. However, keeping track of your objects and practicing good memory management is a much better solution and hacks like this one should be saved for special cases where tracking use of an object becomes difficult or impractical.

Thanks to Alex for the link!

  • http://www.pasz.com adampasz

    What are some examples of when a Weak Reference might be useful?

  • http://losdesigns.com Mims Wright

    adampasz Asked: “What are some examples of when a Weak Reference might be useful?”

    Adam, I’ve added additional text to the above post to answer your question.

  • http://blog.efnx.com Schell

    Weakly referenced Dictionary objects are great but be careful using them to store methods. There’s a glitch in the way Dictionaries resolve references to methods that causes a weakly referenced Dictionary to allow the method to be GC’d immediately. While writing a Queue class I found a nice example. My class can be found here -> blog.efnx.com/?p=37 and this is the code to use in your main timeline to recreate the action.

    function blah(val1:int, val2:int):void
    {
    trace(val1+val2);
    }

    function blah2(val1:int, val2:int):void
    {
    trace(val1+val2);
    }

    var queue:Queue = new Queue(true);
    queue.push(blah, 1, 5);
    queue.push(blah, 2, 5);
    queue.push(blah, 4, 5);
    queue.push(blah2, 3, 5);

    trace(queue);

    var timer:Timer = new Timer(1, 1);
    timer.addEventListener(TimerEvent.TIMER, startQueue, false, 0, true);
    timer.start();

    function startQueue(event:TimerEvent):void
    {
    queue.start();
    trace(queue);
    trace("done");
    }

  • http://losdesigns.com Mims Wright

    Hi Schell,

    I was looking at the code you posted to my site. I wanted to make a few notes that may help out.

    First, the order of the trace has to do with the for…in loop that you use in the toString() method. This loop doesn’t necessarily output in the order you added the functions.

    Second, this isn’t happening as a result of weak references. As you mentioned on your blog post, you cannot use the same function twice as a key without overwriting the previous value. In a Dictionary, the key object acts the same as an index for an array. If you had

    var a:Array = new Array();
    a[0] = “foo”;
    a[1] = “bar”;
    a[1] = “woot”;
    trace(a); // foo,woot

    so it stands to reason that you shouldn’t be able to do this with functions as keys either.

    Since this class essentially runs a list of functions one after the other, you may want to try using dynamic Functions instead. Something like this:

    var func:Function = new Function ():void {
    blah (1, 5);
    blah (2, 5);
    blah (4, 5);
    blah2(3, 5);
    }
    func();

    I hope that was helpful.

  • http://blog.efnx.com Schell

    Yes, I see that my toString() wouldn’t trace the list of functions in the order that they were listed, but without adding another variable to keep track of the order added, how would you trace or execute them first come first serve? It seems like the order it traces in is the same order it executes in.

    Another note: the interesting thing about this class isn’t how the methods are replaced, but because (contrary to posts I had read regarding the matter -> http://gskinner.com/blog/archives/2006/07/as3_dictionary.html) I couldn’t create duplicate function entries with the same method (in a weakly referenced Dictionary).

    My main point was that changing the Dictionary’s reference (weak or strong) changes the output of the code I posted on your blog. For example, changing the code I had posted above to instantiate my Queue class with a ‘strong’ referenced Dictionary, the output is as follows:

    object [Queue]
    -> function Function() {} 3,5
    -> function Function() {} 4,5
    8
    9
    object [Queue]
    done

    As you can see calling toString() on the class traces the contents (in whatever order it decides) and then executes the functions in that same order. Instantiating the class with a weakly referenced Dictionary results in the following:

    object [Queue]
    -> function Function() {} 4,5
    -> function Function() {} 3,5
    object [Queue]
    done

    Here you can see that immediately after pushing the functions into the Queue, the functions can be listed, but after the TimerEvent.TIMER (which is set to 1 millisecond) has triggered, the functions that were once listed are no longer there!

    I may be missing the point, but I never explicitly removed the functions from the queue, yet they disappeared. When the class is instantiated with a strong referenced Dictionary the functions last and are executed. I don’t know what else to attribute this behavior to besides the GC. Maybe you can help me understand this more clearly.

    On a last note, my class is supposed to handle requests from containing classes or extending classes (or the main timeline) that would like to call functions (such as a resize) before those functions are necessarily ready, these functions are most definitely static properties (like a setter function) and declaring dynamic functions aren’t so much an option. One way around this would be to repeat the given function within itself as an alternative dynamic function to execute if the given function can’t operate, passing the dynamic function into the queue, but that seems like it might be complicating the matter… Thanks for pounding this out with me!

  • Pingback: Garbage Collector and Dictionary

  • Kevin

    I see it’s this site’s namesake, but alas the useWeakReference flag described in the second paragraph lies within addEventListener(), not dispatchEvent().

  • Pingback: Norris's Landscape » [转]Flex开发者需要知道的10件事

  • Pingback: Flex开发者需要知道的10件事[转] « Leo

  • Pingback: Flashå’ŒFlex开发者都需要知道的20件事

  • Pingback: Flex开发者需要知道的10件事 | My Sky

  • Pingback: 10条Flex开发人员实用的简单细节事情 | AS3前端