gSkinner - Home

AS3: Resource Management pt 1

Posted on June 19, 2006 by Grant Skinner

I’ve been playing around with AS3 for a while now, and am really excited by its capabilities. The raw execution speed by itself will create so many possibilities. Toss in E4X, Sockets, ByteArrays, new display list model, RegEx, a formalized event and error model, and a few dozen other features for flavour, and you have a pretty heady brew.

With great power comes great responsibility, and this will be very true for AS3. A side effect of all this new control is that the Garbage Collector is no longer able to make as many assumptions about what it should tidy up automatically for you. This means that Flash developers moving to AS3 will need to develop a very strong understanding of how the GC operates, and how to work with it effectively. Building even seemingly simple games or applications without this knowledge can easily result in SWFs that can leak like a sieve, hogging all of a system’s resources (CPU/RAM), and causing the user’s system to hang (potentially even forcing them to hard reboot their computer).

Over the next few weeks (or even months), I will be writing a series of articles on this topic. I will look at the underlying mechanics of the Garbage Collector, discuss the issues you are likely to face, examine the new tools available to you for handling resource management in AS3, and offer solutions/code to help you circumvent many of the common problems you will face.

I’ll begin at the beginning, and look at the Garbage Collector in the Flash 9 player.

About the Garbage Collector

The garbage collector is a behind-the-scenes process that is responsible for deallocating the memory used objects that are no longer in use by the application. An inactive object is one that no longer has any references to it from other active objects. In order to understand this, it is very important to realize that when working with non-primitive types (anything other than Boolean, String, Number, uint, int), you are always passing around a reference to the object, not the object itself – deleting a variable removes the reference, not the object. This is easily demonstrated:

// create a new object, and put a reference to it in a:
var a:Object = {foo:"bar"}
// copy the reference to the object into b:
var b:Object = a;
// delete the reference to the object in a:
delete(a);
// check to see that the object is still referenced by b:
trace(b.foo); // traces "bar", so the object still exists.

If I were to delete “b” as well in the example above, it would leave my object with no active references and free it for garbage collection. The AS3 GC uses two methods for locating objects with no active references: Reference counting and mark sweeping.

Reference Counting

Reference counting is one of the simplest methods for keeping track of active references, and has been around in Flash since AS1. When you create a reference to an object its reference count is incremented. When you delete a reference, its reference count is decremented. If the reference count of an object reaches zero, it is marked for deletion by the GC. For example:

var a:Object = {foo:"bar"}
// the object now has a reference count of 1 (a)
var b:Object = a;
// now it has a reference count of 2 (a & b)
delete(a);
// back to 1 (b)
delete(b);
// down to 0, the object can now be deallocated by the GC

Reference counting is simple, doesn’t carry a huge CPU overhead, and works well in most situations. Unfortunately it really falls down when it comes to circular referencing. This is when objects cross-reference each other (directly, or indirectly via other objects). Even if the application is no longer actively using the objects, their reference counts remain above zero, so they are never removed. Here’s a quick demo:

var a:Object = {}
// create a second object, and reference the first object:
var b:Object = {foo:a};
// make the first object reference the second as well:
a.foo = b;
// delete both active application references:
delete(a);
delete(b);

In the above example, both of my active application references have been deleted. I no longer have any way of accessing the two objects from my application, but their reference counts are both 1 because they reference each other. This can also be much more complex (a references c which references b which references a, etc), and is hard to deal with in code. Flash player 6 and 7 suffered from problems related to circular referencing in XML objects – each XML node referenced both its children and its parent, so they were never deallocated. Fortunately, player 8 added a new GC technique called mark sweeping.

Mark Sweeping

The second strategy employed by the AS3 (and fp8) GC to find inactive objects is mark sweeping. The player starts at the root node of your application (which is conveniently the “root” in AS3), and walks through every reference on it, marking each object it finds. It then iterates through each of the marked objects, marking their children. It continues this recursively until it has traversed the entire object tree of your application, marking everything it finds. At the end of this process, it can safely assume that any objects in memory that are not marked no longer have any active references to them, and can be safely deallocated. You can see how this works in the diagram below (green references were followed during mark sweeping, green objects are marked, white objects will be deallocated).

Mark sweeping is very accurate, but because it has to traverse your entire object structure, it is also costly in terms of CPU usage. Flash player 9 reduces this cost by carrying out iterative mark sweeping (ie. it occurs over a number of frames, instead of all at once), and by only having it run occasionally.

Deferred GC and Indeterminacy

A *very* important thing to understand about the Garbage Collector in FP9 is that it’s operations are deferred. Your objects will not be removed immediately when all active references are deleted, instead they will be removed at some indeterminate time in the future (from a developer standpoint). The GC uses a set of heuristics that look at RAM allocation and the size of the memory stack (among other things) to determine when to run. As a developer, you must accept that fact that you will have no way of knowing when (or even if) your inactive objects will get deallocated. You must also be aware that inactive objects will continue to execute indefinitely (until the GC deallocates it), so code will keep running (ex. enterFrames), sounds will keep playing, loads will keep happening, events will keep firing, etc.

It’s very important to remember that you have no control over when your objects will be deallocated, so you must make them as inert as possible when you are finished with them. Strategies to manage this will be the focus for a future article.

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

Thanks Grant.

I've created an as3 documenter in flex and well we can say there is a lot of internal craziness and things happening.

This article cleared some things up with me about the garbage collector.

I also learned something else and this dosn't have much to do with the GC but does have to do with statelessnes.

I think sometimes when your right in the middle of a large project, you sometimes forget about references to BIG object.

One mistake I made was referencing a FileManager.fileQueueCollection in a quasi analyzer framework. When I started debugging and using ObjectUtil.toString() I realized I thought I was removing references to the .as file's loaded data that I parsed but, I was actually keeping them in memory through a statefull reference back to the FileManager.

This is where that singleton design pattern for managers can really save the day to eleiminate the state references when you just were tired one day and coded something stupid ;-)

Thanks for your insane articles and showing some things that are not directly availble to a lot of developers(IE mechanics of the avm)

Peace, Mike

Posted by: Michael Schmalle on Jun 19, 2006 1:26pm URL: http://www.flex2components.com

very interesting article. THANK YOU! stef

Posted by: stef on Jun 19, 2006 6:41pm

Nice. Very interesting article! Cant wait for futures articles ...

Ales

Posted by: Ales on Jun 20, 2006 1:33am

Really interesting

Perhaps you know something about that : While i use delete in my code, and compiler strict mode on, i've got that error :

Attempt to delete the fixed property a. Only dynamically defined properties can be deleted.

In AS3 Language Reference (for the beta3) there no mention about delete except in Compiler Errors :

1189 > Delete removes dynamically defined properties from an object. Declared properties of a class can not be deleted. This error appears only when the compiler is running in strict mode.

Is it means that only dinamically defined properties can be deleted by this way ?

Does my objects really deleted after calling delete if delete do his job only for dinamically defined properties ?

It seems strange to me, especially after reading your post...

Posted by: Cédric Néhémie on Jun 20, 2006 10:15am URL: http://book.abe.free.fr

Cédric - good question. I started typing a reply, and decided it might warrant it's own post... stand by.

UPDATED: see next post "Understanding the Delete Keyword"

Posted by: Grant Skinner on Jun 20, 2006 10:31am URL: http://gskinner.com/

I'm just wondering why Flash doesn't give you the control of the actual memory now?

It seems it would be easier to delete the object from memory yourself, then to have to disable everything it runs to get it to stop. And then delete.

Very interesting though.

Posted by: UnknownGuy on Jun 21, 2006 11:54am

"they will be removed at some indeterminate time in the future (from a developer standpoint)" .... I'll take it that can mean from several milliseconds to several seconds?

Very interesting article! Curious to read the next one!

Posted by: sascha of H1DD3N.R350URC3 on Jul 5, 2006 8:31pm URL: http://hiddenresource.corewatch.net/

Sascha,

It could be anything from a few milliseconds to hours. It is determined by heuristics that are mostly based on RAM usage. If you carry out a lot of RAM intensive activities, the GC will sweep more often.

Posted by: Grant Skinner on Jul 5, 2006 11:31pm URL: http://gskinner.com/

I am working on Flex migration from 1.5 to 2.0. and i want to delete dynamice property. how can i do it?

Posted by: Devangi on Aug 8, 2006 2:41am

this is exactly the explanation I have been searching for, thank you very much, very beneficial article for flash developers

Posted by: Steve on Sep 19, 2006 11:39am URL: http://www.stevenhargrove.com/

Do you know if FCS/FMS uses only the reference counting method?

Posted by: Nate on Oct 11, 2006 3:36pm

Few thoughts...

Because objects don't get deleted straight away, Ive always taken the approach of setting things I want deleted immediately to null... that way, the object may or may not be deleted straight away, but its contents *are* deleted straight away. That is, 'if you cant delete the container, the next best thing is to make the container empty'.

eg

rather than

delete foo;

I do

foo = null;

delete foo;

Im not sure how valid my assumptions here are, but its certainly reduced the memory usage in a couple of Flash 7 based web applications I've developed in the past, particularly when there's constant XML traffic.

Posted by: Shamb on Jan 4, 2007 3:25am URL: http://weblog.motion-graphics.org/

Shamb,

The delete operator will take care of it; there's no need to set the variable to null. Remember that when you set

foo = {greeting:"Howdy};

and then later on call

foo = null;

What you're doing in the second case is operating on the variable, not the object. If you wanted to clear out the object, you'd have to null out each of the object's properties.

In your case, what you're doing is deleting a variable that's a null reference. Same diff to the garbage collector; the object the variable originally pointed to was already cut loose as soon as you said "foo = null".

Posted by: Chris Luebcke on Mar 26, 2007 12:08pm URL: http://chrisluebcke.com

Shamb - Chris is correct. It should have no impact on the collection of objects whether you set your properties to null or delete them. Both approaches have the effect of removing the reference to the object, not removing (or modifying) the object itself.

Of course, in AS3 you can only delete dynamic properties, so setting to null becomes the norm.

Posted by: Grant Skinner on Mar 26, 2007 8:11pm URL: http://gskinner.com/

this is exactly the explanation I have been searching for, thank you very much, very beneficial article for flash developers

info

Posted by: adam smith on Apr 12, 2007 11:01am URL: http://www.tur-key.info/category/rest/

what's about this

var a:*=new Application();

where application is a class...how can i remove this then ?

Posted by: mirko on May 30, 2007 10:33am URL: http://www.losdospesados.net

We have just updated our game to Flash 9. It has become impossible to play in internet explorer. The problem seems to be that the garbidge collection sweeps the memory every second this makes the processor usage jump between 20% and 80%. This does not happen in other browsers. We have not been able to find a solution.D oes anybody else have this problem with IE / AS3?

Posted by: Joanna Cook on Jul 7, 2007 6:11am URL: http://www.funnytowers.com

Is the GC for JVM and AS work in the same way

Posted by: Gaurav on Jul 21, 2007 11:39pm

Thank you.

Posted by: Evden Eve Nakliyat on Oct 3, 2007 12:49am URL: http://www.aydesign.net

Do Loader objects with event listeners attached (eg Event.COMPLETE) persist as long as the load operation is underway? I have code that includes 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 load event is executed.

Thanks for the article-- very helpful.

Posted by: Dster on Nov 28, 2007 5:59pm

hi i just read your article , very interesting but 1 thing made me very confused ...

in the example where you do :

var a:Object = {foo:"bar"}

var b:Object = a;

delete(a);

delete(b);

right there you are deleting 2 objects that are static right ?

i try it i get the 1189 error (which i was expecting)

so the example doesn't actually work right ?

or am i the only one experiencing this problem ?

by reading the comments i guess i should do

a = null;b = null; to make it eligable for deallocation ?

Posted by: Aaike on Jan 16, 2008 11:22am

These are just the kind of headaches that the java applet community went through (the past tense refers more to the death of java applet development, rather than the problems ever being solved)

Considering Flash's background as an creative tool that traditionally allowed loose coding standards, I'm surprised Adobe allowed this backdoor to remain so open. Along with the recent security issues, allowing untrusted code that is assumed to run in a sandbox to bring down the VM and/or the OS, could tarnish Flash reputation as a must have plugin. Rather corporate IT administrators may start to view it in the same light as they do Java applet plugin, and a drop in corporate desktop (ie middle income advert viewers) penetration will hurt the whole flash development industry.

There are some pretty hardcore memory management debugging tools for java, including those that emulate the garbage collectors sweep through the object tree, so developers can see linkages that prevent unloading.

Grant, can you give us some clues as to what will be coming up in your Strategies and Solutions post?

Posted by: Jake Lewis on Apr 15, 2008 8:05am

Wery nice article.

Thanks!!

Posted by: Aram on Jun 19, 2008 4:12am

hi,i have a question about addeventlistener

obj.addEventLisener(..listener);

obj = null;

i want to know why gc won't clean obj?

i think addlistener means obj have a reference to listener (function object), just like obj have other parameters, when obj is null, no reference to obj, so gc should clean obj

or addlistener, the listener(function obj) will have a reference to the obj? or other reasons?

Posted by: sshong on Jul 4, 2008 12:03am URL: http://www.asarea.cn

hehe,that great. thanks.

Posted by: laan on Oct 28, 2008 12:11am URL: http://www.laaan.cn

Great article Grant - as usual. Hey what plans for the UML tool extension plans for AS3?

Posted by: aYo on Nov 8, 2008 3:33pm URL: http://designstreet.net

where's the last article with title "Strategies and Solutions"?...this is really wierd.

Posted by: BlueF on Nov 10, 2008 9:19am URL: http://bluef.org

Wow! this actually really makes sense.

So - since I can't in no way controll a thing in flash - How do I go about deleting those stinky things?

Posted by: grabek on Nov 27, 2008 6:25am URL: http://www.compelo.com/

hi

how this garbage collections are used in our loader or the Movieclips?..

Thanks

Karthick Raj.S

Posted by: Karthick on Dec 5, 2008 10:50pm

Useful, Nice Informational Article.

Posted by: Kuldip D Gandhi on Feb 5, 2009 7:59am URL: http://Kuldip.deviantart.com

This post comes up in the google search result "as3 memory management" right in the first place. You should update it to the present reality of the Flash Player 10, even if we must have the same careful approach with the new player, if I'm not wrong we have new things like invoking System.gc() among others? How to use System.gc() efficiently?

Posted by: antonio brandao on Feb 8, 2009 1:31pm URL: http://www.antoniobrandao.com/

Great article. Looks like there are issues when the GC don´t work properly when using bytesArray and swfloaders. Deleting swfloaders or clearing them from data won´t always "mark" loaded data (note: loaded with byteAray) as garbage. Very odd.

Posted by: jema on Apr 8, 2009 8:45am

This article is just curiously, i think.

who could give some sample, a full-application, which is optimized with the numerous waste resources?

Posted by: who on Jun 2, 2009 9:59pm

Great article. Thanks for sharing this info. Somehow, adobe's own documentation lacks in clarifying certain things.

Posted by: Sharad on Jun 30, 2009 12:08am

No one replied to Aaike's post on January 16, 2008. I am getting the same problem as hers! I get the 1189 error, basically.. delete a, and delete b do NOT work and I turn into an error. It only works if I do

delete a.foo

delete b.foo

So in response to mine and Aaike's post , will the GC collect the garbage if we set a = null, and b = null as well? Simple question deserves a simple answer. Thanks =)!

Posted by: Rick on Jun 30, 2009 7:46pm

I did use some smart garbarge collection in my Smooth xml image gallery: http://bit.ly/7aWzXt ; it took a lot of time to set everything straight :)

Posted by: flashSpec on Dec 17, 2009 9:47am URL: http://bit.ly/7aWzXt

I came across the following "feature" in Flash 10, compiling with Flash IDE CS4:

Take the following code as your starting position:

//-------------------

var obj:Object = new Object();

var prev:int = 0;

trace( 'var obj:Object = new Object();\t--> ' + System.totalMemory );

prev = System.totalMemory;

obj.sound = new Sound();

trace( 'obj.sound = new Sound();\t\t--> '+ System.totalMemory + '('+(prev ' + System.totalMemory + '('+(prev

Posted by: KolNedra on Dec 28, 2009 3:58am URL: http://www.kolnedra.com

I would absolutely love to be able to view those reference counts in a debugger.

Posted by: Mark on Jun 9, 2010 5:07pm

Mark, have you checked out the profiler in Flash Builder? It will give you the number of references, where they're from, etc.

Posted by: Aaron Hardy on Jul 21, 2010 7:59pm URL: http://aaronhardy.com

Thanks, it’s very helpful for me.
http://www.as3tutorial.com is very helpful for beginners.

Posted by: ZREN on Jan 13, 2011 1:38pm URL: http://www.as3tutorial.com

I would absolutely love to be able to view those reference counts in a debugger.

Posted by: altın çilek on Jan 24, 2011 8:13am URL: http://www.altincilek.tk

This blog is dead. And you will be dead soon too (not really)

Posted by: Blog UnderTaker on Feb 2, 2011 5:31am