Garbage Collection and Weak References

First off: A wonderful series of articles by Grant Skinner about the new concerns regarding Garbage Collection in AS3. This can not be ignored if your doing AS3 coding.

AS3: Resource Management pt 1
AS3: Resource Management pt 2
AS3: Resource Management pt 3
AS3: Weakly Referenced Listeners

But, I’m going to quote here an excerpt from Part 3 above about Weak References:

Weak References
One of the features I’m really happy to see implemented in AS3 is weak references. These are references to objects that are not counted by the Garbage Collector in determining an object’s availability for collection. That is, if the only references remaining to an object are weak, that object will be removed by the GC on its next pass. Unfortunately, weak references are only supported in two contexts. The first is event listeners, which is great because event listeners are one of the most common references that cause problems with garbage collection. I strongly recommend always using weak references with listeners by passing true as the fifth parameter of your addEventListener calls:

someObj.addEventListener("eventName",listenerFunction,useCapture,priority,weakReference);
stage.addEventListener(Event.CLICK,handleClick,false,0,true);
// the reference back to handleClick (and this object) will be weak.

To learn more, read my article on weakly referenced listeners.

The other place that weak references are supported is in the Dictionary object. Simply pass true as the first parameter when you instantiate a new Dictionary to have it use weak references as its keys:

var dict:Dictionary = new Dictionary(true);
dict[myObj] = myOtherObj;
// the reference to myObj is weak, the reference to myOtherObj is strong

To learn more about using dictionaries in ActionScript 3, read my article about the Dictionary Object in AS3. One of the cool things about having weak reference support in Dictionary is that we can hook into it to use weak references in other contexts. For example, I used Dictionary to create WeakReference and WeakProxyReference classes that can be used to create weak references anywhere.

WeakReference class
WeakReference takes advantage of Dictionary to allow you to hold a weak reference to any object within any context. It has a small amount of overhead for instantiation and access, so I would only recommend using it for potentially large objects that may not be properly freed. This should not replace writing code that cleans up properly after itself, but it can help you to ensure large data objects are freed properly for garbage collection.

I based the ActionScript 3 WeakReference class on the WeakReference class for Java. To use it, you simply instantiate a new WeakReference, passing the referent (object you wish to reference) as the first parameter. You then store a strong reference to the instance of WeakReference, not the referent, and access the referent via the get() method of WeakReference.

import com.gskinner.utils.WeakReference;
var dataModelReference:WeakReference;
function registerModel(data:BigDataObject):void {
   dataModelReference = new WeakReference(data);
}
...
function doSomething():void {
   // get a local, typed reference to the data:
   var dataModel:BigDataObject = dataModelReference.get() as BigDataObject;
   // call methods, or access properties of the data object:
   dataModel.doSomethingElse();
}

For well architected code, this is a good solution, because it lets you maintain type safety, and is non-ambiguous. For those who just want to hack code together quickly, I also put together the WeakProxyReference class (which was a great learning experience for the new Proxy object).

WeakProxyReference class
WeakProxyReference uses the new Proxy class to transparently wrap a weakly referenced object. It works the same as WeakReference, except that you can call methods on the weak reference object directly and have them passed to the referent. The main issues are the loss of type safety, and slightly more ambiguous code. Note that it will still throw appropriate run-time errors (ex. if you try to access a non-existent property on the object), but not compile-time errors.

import com.gskinner.utils.WeakProxyReference;
var dataModel:Object; // note that it is untyped, and not named as a reference
function registerModel(data:BigDataObject):void {
   dataModel = new WeakProxyReference(data);
}
function doSomething():void {
   // don't need to get() the referent, you can access members directly on the reference:
   dataModel.doSomethingElse();
   dataModel.length++;
   delete(dataModel.someProperty);

   // if you do need access to the referent, you need to use the weak_proxy_reference namespace:
   var bdo:BigDataObject = dataModel.weak_proxy_reference::get() as BigDataObject;
}

Unsupported Way to Force GC
In my previous article on Garbage Collection in AS3 I said that the GC is indeterminate - that there is no way to know when it will run. That is not entirely true, there is a trick that will let you force the Flash player to carry out a full GC pass. This trick can be really handy for exploring Garbage Collection, and testing your applications during development, but it should never be deployed in production code because it can wreak havoc with processor load. It is also officially unsupported, so you cannot rely on it to work in updated versions of the player.

To force an immediate GC mark/sweep, all you have to do is call connect() on two LocalConnections with the same name. This will throw an error, so you’ll have to wrap it in a try/catch block.

try {
   new LocalConnection().connect('foo');
   new LocalConnection().connect('foo');
} catch (e:*) {}
// the GC will perform a full mark/sweep on the second call.

Again, this should only be used as a development aid. It should never be used in production code! There is an example of this in use in the demo FLAs for the WeakReference class, which you can download at the end of this article.

Summary
ActionScript 3 has substantially increased the amount of work developers must do to manage resources in their applications. While we have only been provided with a few new tools to help us with this, they are better than nothing and signify that Adobe is at least aware of the issue. Pairing these new tools with effective strategies and approaches (the subject of my next article) should allow you to successfully manage resources in Flash 9 and Flex 2 projects.

A big thank you to Thomas Reilly for proofreading this article, and ensuring I’m not misleading the rest of the Flash world too badly. Any errors are mine, not his.


 
 
 

Leave a Reply

You must be logged in to post a comment.