|
|
Weak vs Strong References in AS3 |
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.dispatchEvent() 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 [
eventDispatch()method's]useWeakReferenceflag to true, you will create a weak link between the event broadcaster and the event listener. That way, if an event listener is deleted while still listening to the event broadcaster, 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
[ftf]
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 {}
[/ftf]
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!
December 9th, 2007 at 11:03 am
What are some examples of when a Weak Reference might be useful?
December 9th, 2007 at 5:33 pm
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.
December 10th, 2007 at 1:55 am
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");
}
December 14th, 2007 at 1:04 pm
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.
December 16th, 2007 at 8:17 am
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!
July 17th, 2008 at 7:59 pm
[...] Weak references are cool. No. they are substantial. I don’t know how we lived without them before. Anyway, they made our (we = flash developers) life better. I use them very often, when adding event listeners or caching with dictionaries (and I’m sure I’d use them even more often if there was any more possibilty provided). [...]